4

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);
13
  • I can define char **pp={ "123", "456", "789" }; .. What compiler are we talking about? Commented May 29, 2015 at 14:32
  • What is the purpose of using ++(**pointerToPointer) ? Commented May 29, 2015 at 14:33
  • 1
    @EugeneSh. , With warnings though... Commented May 29, 2015 at 14:35
  • 1
    "And why I can't increment ++(**pointerToPointer);" Because the strings you have are string literals and they are immutable. Commented May 29, 2015 at 14:36
  • 1
    @Subinoy , Because of this. Fix it by this Commented May 30, 2015 at 8:23

2 Answers 2

2

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 (i.e. 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" };
Sign up to request clarification or add additional context in comments.

Comments

1

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.

8 Comments

one array means? @CoolGuy Please edit it if you see any mistakes
char *pp[]={ "123", "456", "789" }; declares an array of pointers, each of type char*. Actually, 4 arrays can be seen here ( I was wrong ), Each string literal is an array as well.
Yeah it get out of my, I have edited it. I just forget the concept. Sorry for mistakes @CoolGuy
Isn't there are three arrays?@CoolGuy
Four. Three strings "123","456","789" and pp.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.