What is the syntax for pointers

12.9 Pointers to pointers and string tables

"Pointer to pointer" is a difficult subject, but it is worth understanding. The syntax of pointers to pointers looks like this:

What does "pointer to pointer" mean exactly? You have a pointer that points to a pointer that points to a variable and can access that variable. In technical jargon, multiple indirection is used. In theory, it is also possible to use pointers to pointers to pointers and so on. In practice, however, such multiple indirections hardly make sense. Most of the time you use pointers to pointers, that is, two dimensions.

The main area of ​​application of pointers to pointers is the dynamic generation of multidimensional arrays such as matrix calculations. But that's what I'll cover in Chapter 14, "Dynamic Memory Management."

Let's first look at an example on this complex topic:

/ * ptrptr1.c * / #include #include int main (void) {int value = 10; / * ptr is worth a pointer to int. * / int * ptr = & value; / * ptr_ptr is a pointer to the pointer int * ptr. * / int ** ptr_ptr = & ptr; printf ("* ptr:% d \ n", * ptr); printf ("** ptr_ptr:% d \ n", ** ptr_ptr); / * Changes the value pointed to by int * ptr. * / ** ptr_ptr = 100; printf ("* ptr:% d \ n", * ptr); printf ("** ptr_ptr:% d \ n", ** ptr_ptr); / * Changes the value again. * / * ptr = 200; printf ("* ptr:% d \ n", * ptr); printf ("** ptr_ptr:% d \ n", ** ptr_ptr); return EXIT_SUCCESS; }

In this example it is important that you use the double indirection operator (**) when changing the variable, just like when declaring the pointer to a pointer. You would have instead

Wrote the following:

the pointer ptr_ptr would point to memory address 100. And this is mostly somewhere in the nirvana of memory. As I said, this topic is taken up again in Chapter 14, and it will make a lot more sense to you there.

12.9.1 String tables

To make it even more complicated now, I want to add the string tables, which are not dissimilar to pointers to pointers (but are not the same!).

An example: The following string constants are to be sorted alphabetically (without using the header file ):

"Zeppelin", "Auto", "America", "Programming"

You remember that * ptr represents the same start address as ptr [0]. And the same now also applies to:

So you have an array of pointers. And this would look like this in the example:

char * sort [] = {"Zeppelin", "Car", "America", "Programming"};

Here you have what is known as a string table. How can the individual strings of a string table be accessed now? Here is a small example:

/ * ptrptr2.c * / #include #include int main (void) {char * sort [] = {"Zeppelin", "Car", "America", "Programming"} ; printf ("% s \ n", sort [1]); / * Auto * / printf ("% s", (sort [2] +2)); / * erika * / printf ("% s% s \ n", (sort [0] +6), sort [2]); / * in America * / printf ("%. 5s \ n", (sort [3] + 5-2)); / * gram * / return EXIT_SUCCESS; }

Figure 12.18 Use of a string table

Access to the string table is similar to that of the multi-dimensional arrays. The first edition

puts the word "car" on the screen. It can therefore be assumed that

sort [0] = "Zeppelin" sort [1] = "Auto" sort [2] = "America" ​​sort [3] = "Programming"

using the indexing operator to refer to the starting addresses of the individual strings. With the second statement

printf ("% s", (sort [2] + 2));

the name »erika« is displayed. This can be explained as follows: sort [2] represents the starting address of "America", ie "A". Then +2 is added after the field index. The pointer, which would have continued to point to the beginning of "America" ​​without +2, now points to the third letter of the word, ie to "e". Or more precisely: to the address of "e". The format character% s then causes the string to be displayed on the screen from this address onwards. This will be the same for the next issue. The spelling

printf ("% s \ n", (sort [3] + 5 - 2));

only serves to demonstrate that it can be done that way. Of course, this is easier to read with:

printf ("% s \ n", (sort [3] + 3));

The program is to be demonstrated again using addresses:

/ * ptrptr3.c * / #include #include int main (void) {char * sort [] = {"Zeppelin", "Car", "America", "Programming"} ; printf ("% p =% c \ n", ** sort, ** sort); printf ("% p =% c \ n", * sort [0], * sort [0]); printf ("% p =% c \ n", * (sort [0] +0), * (sort [0] +0)); printf ("% p =% s \ n", sort [0], sort [0]); printf ("% p =% s \ n", * sort, * sort); printf ("% p =% s \ n", (sort [0] +1), (sort [0] +1)); printf ("% p =% s \ n", (sort [0] +2), (sort [0] +2)); printf ("* sort =% p, ** sort =% p \ n", * sort, ** sort); return EXIT_SUCCESS; }

Figure 12.19 Output of the addresses of a string table

The first three issues

printf ("% p =% c \ n", ** sort, ** sort); printf ("% p =% c \ n", * sort [0], * sort [0]); printf ("% p =% c \ n", * (sort [0] +0), * (sort [0] +0));

the (start) addresses and contents to which the second pointer points were always used - which the output confirms. Then only the address of the first pointer is used:

printf ("% p =% s \ n", sort [0], sort [0]); printf ("% p =% s \ n", * sort, * sort);

The content is of course the same when using one pointer as when using two pointers. But when the program is compiled, both pointers have a different address. The output of

printf ("* sort =% p, ** sort =% p \ n", * sort, ** sort);

confirms all of this again. Each individual pointer therefore needs its own storage space and therefore its own address. I'll try to explain it differently again:

This points to the yth character in the xth string. The program looks like this:

or - as already known - like this:

This would refer to the 3rd character in the 2nd string, which corresponds to the "t" character from the "Auto" string.

Now this string table is to be sorted alphabetically. The whole line of text is not shifted and copied back and forth unnecessarily, only the pointers have to be put in the correct order:

/ * ptrptr4.c * / #include #include #include int main (void) {char * sort [] = {"Zeppelin", "Auto", " America "," Programming "}; int i, j; char * temp; for (i = 0; i <4; i ++) {for (j = i + 1; j <4; j ++) {if ((strcmp (sort [i], sort [j])> 0)) {temp = sort [i]; sort [i] = sort [j]; sort [j] = temp; }}} for (i = 0; i <4; i ++) printf ("% s \ n", sort [i]); return EXIT_SUCCESS; }

This sorting algorithm is called »Selection Sort«. The following lines sort the fields with pointers:

for (i = 0; i <4; i ++) {for (j = i + 1; j <4; j ++) {if ((strcmp (sort [i], sort [j])> 0)) {temp = sort [i]; sort [i] = sort [j]; sort [j] = temp; }}}

First, the first element in the string table is compared with all the others. This will find the smallest element that is placed at the beginning. Then the second element is compared with all the elements in front of it. This continues until the last element in the string table. You can find more about the algorithms in Chapter 22.

The most important thing - as has already been mentioned several times - is that pointers are there for addresses and nothing else. For example means

nothing more than a char array with 500 char pointers. More precisely, each of these 500 pointers can e.g. B. point to a string (char array). Need proof? Here you go:

/ * ptrptr5.c * / #include #include int main (void) {char * text [500]; char str1 [] = "Text1"; char str2 [] = "Text2"; char str3 [] = "Text3"; text [0] = str1; text [1] = str2; text [2] = str3; printf ("% s% s% s \ n", text [0], text [1], text [2]); return EXIT_SUCCESS; }

In this example, the start address of a string constant was transferred to the first three pointers. This was not possible with simple arrays. Of course, it is not yet possible to assign the start address of a text created during runtime in this way. To do this, you need knowledge of dynamic memory management.

When it came to sorting strings, the pointers to the starting address of the strings could be sorted much more effectively (faster) than if this were done with the entire string. This is due to the fact that only addresses on a string are used.

And instead of

char * sort1 = "Zeppelin"; char * sort2 = "car"; char * sort3 = "America"; char * sort4 = "Programming";

to write, is this notation

char * sort [] = {"Zeppelin", "Car", "America", "Programming"};

much more effective and shorter. Here there are four pointers to a char array that point to the start address of each individual word.

The programmer has the following advantages when he uses string tables:

  • The program becomes clearer with string tables.
  • It saves storage space.
  • The management of string tables is easier and more efficient.
  • If a program is written in several languages, this can be localized more easily.

Here is an example of how you can use string tables effectively:

/ * ptrptr6.c * / #include #include #define ASK 0 #define WORDS 1 #define START 2 #define ENGLISH 1 #ifdef GERMAN const char * language [] = {"Du speak German? "," Some words: "," Fire "," Earth "," Water "," Air "," Life ", ZERO}; #elif ENGLISH const char * language [] = {"Do you speak english?", "Some words:", "Fire", "earth", "water", "air", "life", NULL}; #else / * FRENCH * / const char * language [] = {"Tu parle francais?", "quelques mots:", "Le feu", "La terre", "de l'eau", "de l'air "," La vie ", NULL}; #endif int main (void) {int i; printf ("% s \ n", language [ASK]); printf ("% s \ n", language [WORDS]); for (i = START; language [i]! = NULL; i ++) printf ("\ t% s, \ n", language [i]); return EXIT_SUCCESS; }

This is a simple listing that translates a program into the appropriate language with conditional compilation. In this example,

the language is set to English. This is also confirmed when the program is issued. If you now have to write a version for your Spanish colleague, all you have to do is search for the string table and translate and add the appropriate entries. This is how an international program is created without too much effort:

#ifdef GERMAN const char * language [] = {"You speak German?", "Some words:", "Fire", "Earth", "Water", "Air", "Life", ZERO}; #elif ENGLISH const char * language [] = {"Do you speak english?", "Some words:", "Fire", "earth", "water", "air", "life", NULL}; #elif FRENCH const char * language [] = {"Tu parle francais?", "quelques mots:", "Le feu", "La terre", "de l'eau", "de l'air", "La vie ", NULL}; #else / * ESPANOL * / const char * language [] = {"Habla Usted espanol", "algunas palabras:", "Fuego", "tierra", "agua", "aire", "vida", NULL}; #endif

String tables can also be used to conveniently display error messages on the screen:

char * error message [] = {"Insufficient memory space", "Memory range exceeded", "Value range exceeded", "The syntax seems incorrect", "Access denied - no rights", "Access denied - wrong password", "Unknown error occurred" };

The individual error messages are accessed with the field index from No. [0] - [6]. "Access denied - no rights", for example, is an error message [4].

After this section about pointers to pointers and the string tables, one or the other question will surely come up. Above all, the examples were always given with constant values. So in order to deal with the topic effectively and sensibly, you have to be patient a little longer until you get to (I repeat myself) dynamic memory management (Chapter 14).

your opinion

How did you like the Openbook? We always look forward to your feedback. Please send us your feedback as an e-mail to [email protected]