Arrays of Pointers

9.4 Arrays of Pointers

As seen in the last example, sorting an array of strings requires swapping the strings which can require copying a lot of data. For efficiency, it is better to avoid actual swapping of data whenever a data item is large, such as a string or an entire data base record. In addition, arrays may be needed in more than one order; for example, we may need an exam scores array sorted by Id number and by weighted scores; or, we may need strings in both an unsorted form and a sorted form.
In either of these cases, we must either keep two copies of the data, each sorted differently, or find a more efficient way to store the data structure. The solution is to use pointers to elements of the array and swap pointers. Consider some examples:

int data1, data2, *ptr1, *ptr2, *save;
data1 = 100; 
data2 = 200; 
ptr1 = *data1; 
ptr2 = *data2;

We could swap the values of the data and store the swapped values in data1 and data2 or we could simply swap the values of the pointers:

save = ptr1;
ptr1 = ptr2;
ptr2 = save;

We have not changed the values in

data1

and data2 but ptr1 now accesses data2 and ptr2 access data1. We have swapped the pointer values so they point to objects in a different order. We can apply the same idea to strings:

char name1[] = "John";
char name2[] = "Dave";
char *p1, *p2, *save;
p1 = name1; 
p2 = name2;

Pointers p1 and p2 point to strings name1 and name2. We can now swap the pointer values so p1 and p2 point to name2 and name1, respectively.

In general, an array of pointers can be used to point to an array of data items with each element of the pointer array pointing to an element of the data array. Data items can be accessed either directly in the data array, or indirectly by dereferencing the elements of the pointer array. The advantage of a pointer array is that the pointers can be reordered in any manner without moving the data items. For example, the pointer array can be reordered so that the successive elements of the pointer array point to data items in sorted order without moving the data items. Reordering pointers is relatively fast compared to reordering large data items such as data records or strings. This approach saves a lot of time, with the additional advantage that the data items remain available in the original order. Let us see how we might implement such a scheme.

STRPTRS: Given an array of strings, use pointers to order the strings in sorted form, leaving the array unchanged.

We will use an array of character pointers to point to the strings declared as follows:

char * nameptr[MAX];

The array, nameptr[], is an array of size MAX, and each element of the array is a character pointer. It is then possible to assign character pointer values to the elements of the array; for example:

nameptr[i] = "John Smith";

The string "John Smith" is placed somewhere in memory by the compiler and the pointer to the string constant is then assigned to nameptr[i]. It is also possible to assign the value of any string pointer to nameptr[i]; for example, if s is a string, then it is possible to assign the pointer value s to nameptr[i]:

nameptr[i] = s;

In particular, we can read strings into a two dimensional array, names[][], and assign each string pointer, names[i] to the element of the pointer array, nameptr[]:

for (i = 0; i < MAX && gets(names[i]); i++)
          nameptr[i] = names[i];

The strings can then be accessed either by names[i] or by nameptr[i] as seen in Figure 9.4. We can then reorder the pointers in nameptr[] so that they successively point to the strings in sorted order as seen in Figure 9.4. We can then print the strings in the original order by accessing them through names[i]and print the strings in sorted order by accessing them through nameptr[i]. Here is the algorithm

/**
 * Zadania
 * -------
 * z1: Napisz program, który pokazuje, które atrybuty procesu macierzystego są dziedziczone przez proces potomny  uruchomiony za pomocą funkcji fork(), które zaś otrzymują nową wartość.
 * z2: Napisz program, który pokazuje, które atrybuty procesu są zachowane przez proces po wykonaniu funkcji exec().
 * z3: Napisz program, który wyświetla identyfikator procesu (PID) i nazwę związanego z nim polecenia dla wszystkich procesów uruchomionych przez użytkownika podanego w wierszu wywołania programu. Wskazówka: informacje te można uzyskać przeglądając katalog /proc z plików (interesują nas katalogi, których właścicielem jest dany  użytkownik) i pliki /proc/PID/status
 *
 * Każdy proces charakteryzuje się pewnymi atrybutami. Należą do nich:
 * Identyfikator procesu PID
 * Identyfikator procesu macierzystego PPID
 * Rzeczywisty identyfikator właściciela procesu
 * Rzeczywisty identyfikator grupy procesu
 * Efektywny identyfikator właściciela procesu
 * Efektywny identyfikator grupy procesu
 * Katalog bieżący i katalog główny
 * Maska tworzenia pliku
 * Identyfikator sesji
 * Terminal sterujący
 * Deskryptory otwartych plików
 * Ustalenia dotyczące obsługi sygnałów
 * Ustawienia zmiennych środowiskowych
 * Ograniczenia zasobów
 *
 *
 * Potomek dziedziczy z procesu potomnego wiele własności:
 rzeczywisty identyfikator użytkownika, rzeczywisty identyfikator grupy, obowiązujący identyfikator użytkownika, obowiązujący identyfikator grupy,
 identyfikatory dodatkowych grup,
 identyfikator sesji,
 terminal sterujący,
 sygnalizator ustanowienia identyfikatora użytkownika oraz sygnalizator ustanowienia identyfikatora grupy,
 deskryptory otwartych plików (są kopiowane)
 bieżący katalog roboczy,
 katalog główny,
 maskę tworzenia plików,
 maskę sygnałów oraz dyspozycje obsługi sygnałów,
 sygnalizator zamykania przy wywołaniu funkcji exec (close-on-exec) dla wszystkich otwartych deskryptorów plików,
 środowisko,
 przyłączone segmenty pamięci wspólnej,
 ograniczenia zasobów systemowych.
 Są jednak pewne różnice między procesem macierzystym a potomnym:
 wartość powrotu z funkcji fork,
 różne identyfikatory procesów,
 inne identyfikatory procesów macierzystych - w procesie potomnym jest to identyfikator procesu macierzystego; w procesie macierzystym identyfikator procesu macierzystego nie zmienia się,
 w procesie potomnym wartości tms_utime, tms_cutime i tms_ustime są równe 0,
 potomek nie dziedziczy rygli plików, ustalonych w procesie macierzystym,
 w procesie potomnym są zerowane wszystkie zaległe alarmy,
 w procesie potomnym jest zerowany zbiór zaległych sygnałów.
 */

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

extern char** environ;
char *prt_parent;

int glob = 1;           // zewnętrzna zmienna

/* Prints the environment, one environment variable to a line, of the process given by PID. */
char *print_process_environment(pid_t pid) {
    int fd;
    char filename[24];
    char environment[8192];
    size_t length;
    char* next_var;
    /* Generate the name of the environ file for the process. */
    snprintf(filename, sizeof(filename), "/proc/%d/environ", (int) pid);
    /* Read the contents of the file. */
    fd = open(filename, O_RDONLY);
    length = sizeof(environ);
    printf("Size of environ: %d\n", length);
    close(fd);
    /* read does not NUL-terminate the buffer, so do it here. */
    environment[length] = '\0';
    /* Loop over variables. Variables are separated by NULs. */
    next_var = environment;
    while (next_var < environment + length) { /* Print the variable. Each is NUL-terminated, so just treat it like an ordinary string. */ printf(">> %s\n", next_var);
        /* Advance to the next variable. Since each variable is
         NUL-terminated, strlen counts the length of the next variable,
         not the entire variable list. */
        next_var += strlen(next_var) + 1;
    }
    return (environment);
}


int main(int argc, char **argv) {
    int var = 100;              // zmienna automatyczna na stows
    char **env = environ;       // środowisko parent
    // zapamiętanie environ w tablicy

    printf("PROGRAM Z1\n\n");
    printf("Zmienne srodowiskowe parent: ----------------------------\n");
    while (*env) {
        printf("%s\n", *env++);
    }

    printf("---------------------------------------------------------\n");
    
    for (int i = 0; *env != NULL && gets(env[i]); i++)
              nameptr[i] = env[i];
    
    pid_t pid = fork();

    if (pid == 0) {
        // child process
        glob++;
        var++;
        printf("child process: pid %d, ppid %d, getuid %d, geteuid %d, getgid %d, glob = %d, var = %d\n", getpid(), getppid(), getuid(), geteuid(), getgid(),
                glob, var);

        /**
         * wy swietlenie zmiennych środowiskowych różnych od parent
         */
        printf("Zmienne srodowiskowe child różne od parent:\n");
        char environment_1[8192];
        char * prt_env = &environment_1;
        prt_env = print_process_environment(pid);
        char **env_child = environ;
        printf("Size of *char: %d\n", sizeof(environ));

        while (*env_child) {
            printf("compare - %s %d\n", *env_child, strcmp(*env_child++, *env++));
            //printf("%s -----\n", *env2++);
            //if (strcmp(*env2, ++*env) == 0) {
            //
            //} else {
            //printf("%s jest takie samo\n", *env2);
            //}
            //*env_child++;
            //*env++;
        }
        printf("-------------------- x --------------------\n");

    } else if (pid > 0) {
        // parent process
        printf("parent process: pid %d, ppid %d, getuid %d, geteuid %d, getgid %d, glob = %d, var = %d\n", getpid(), getppid(), getuid(), geteuid(), getgid(),
                glob, var);
    } else {
        // fork failed
        printf("fork() failed!\n");
        return (1);
    }

    printf("-- end of program pid %d\n", getpid());

    return (0);
}

Hits: 0

Proudly powered by WordPress | Theme: Baskerville 2 by Anders Noren.

Up ↑