简体   繁体   中英

C - char array and char pointer

Why I can't define an array

char **pp={ "123", "456", "789" };

But I can define it as a char*[] ,and send it to a function that will accept it as a char **

char *pp[]={ "123", "456", "789" };
fun(pp);

void fun(char **pointerToPointer)
{
    //++(**pointerToPointer);//error
    printf("%s", *pointerToPointer); 
}
//output::"123"

And why I can't increment

++(**pointerToPointer);

To answer the first question, the principles might be clearer if we use a single depth of pointer. This code is illegal for the same reason:

int *ptr = { 1, 2, 3 };

In C, a braced initializer list is not an object (especially not an array). It can only be taken as a list of items from which to read initializers when an object is being initialized.

ptr is one object, so at most one initializer could be taken, and the expected form of that initializer is a pointer (which 1 is not).

In fact this code is explicitly illegal under C11 6.7.9/11:

The initializer for a scalar shall be a single expression, optionally enclosed in braces

However, there is a gcc bug/feature where it permits excess initializers for a scalar and ignores them. Further, some compilers may "be helpful" and "only" issue a warning, and initialize ptr to point to address 1 , wherever that might be.

"scalar" means an object that's not a struct or an array.


Since C99 you can write:

int *ptr = (int []){1, 2, 3};

which creates an array (using the same storage duration as ptr ) and points ptr at its first element.

This array is mutable; for a non-mutable one use int const *ptr = (int const[]){1, 2, 3}; instead.


Replacing int by char * , we see that you could write:

char **p = (char *[]){ "123", "456", "789" };

in which case the pointers in the array are mutable, but the things they point to (ie the string literals) still aren't.

Note that you should always use char const * when dealing with string literals, because they are not mutable. The fact that string literals have type char [N] is a historical hangover from before const was added to C. So:

char const **pp = (char const *[]){ "123", "456", "789" };

or with non-mutable pointers to strings:

char const *const *pp = (char const *const []){ "123", "456", "789" };

Here char *pp[]={ "123", "456", "789" }; is correct because:

  • Here it is an array of pointers which 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.
  • As we assign each array to a char pointer, it works fine.

But in case of char **pp={ "123", "456", "789" };

  • Here the memory initialization is not happening.
  • Instead of this first string is assigned to the pointer and then compiler generates warning saying other many values are discarded.

As CoolGuy said ++(**pointerToPointer) it is error because it accessing 1 of "123" string, and trying to change the value of 1 to 2 , and as these are string literals assigning can't be done. You can only see the increment value of print: printf("%c\\n", **pointerToPointer+1); which will give output : 2

You can solve it by the solution provided by CoolGuy in the comment-

  1. By changing char *pp[]={ "123", "456", "789" }; to char pp[][100]={ "123", "456", "789" };
  2. By changing void fun(char **pointerToPointer) to void fun(char (*pointerToPointer)[100])

It is correct because here the value of **pointerToPointer is getting changed.

These are the reasons to me. And for the warning:

warning: excess elements in scalar initializer [enabled by default]

you can see the link in here which is the best explanation of it to me.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM