15
char *p = "some string"   

creates a pointer p pointing to a block containing the string.

char p[] = "some string" 

creates a character array and with literals in it.

And the first one is a constant declaration.Is it the same of two-dimensional arrays?

what is the difference between

char **p,char *p[],char p[][]. 

I read a bit about this that char **p creates an array of pointers so it has an overhead compared to char p[][] for storing the pointer values.

the first two declarations create constant arrays.i did not get any run time error when i tried to modify the contents of argv in main(int argc,char **argv). Is it because they are declared in function prototype?

Gangadhar
  • 10,248
  • 3
  • 31
  • 50
programer8
  • 567
  • 1
  • 6
  • 17
  • 4
    This stuff is incredibly confusing. It's first important to understand that the term "creates" must be used with great caution -- "declares" is *not* the same as "creates". – Hot Licks Oct 11 '13 at 18:57
  • 1
    Read section 6 of the [comp.lang.c FAQ](http://www.c-faq.com/). – Keith Thompson Oct 11 '13 at 19:07
  • by "creates" i mean declares and initializes.or "defines". – programer8 Oct 11 '13 at 19:14
  • @KeithThompson that's a nice link.i am going through it. – programer8 Oct 11 '13 at 19:14
  • 2
    This has already been discussed countless times. Please do some research before asking. –  Oct 11 '13 at 19:21
  • 1
    Pay particular attention to the fact that `char foo[]` has a different meaning as an object declaration and as a parameter declaration. – Keith Thompson Oct 11 '13 at 19:29
  • possible duplicate of [C: differences between char pointer and array](http://stackoverflow.com/questions/1335786/c-differences-between-char-pointer-and-array) and [C pointer to array/array of pointers disambiguation](http://stackoverflow.com/questions/859634/c-pointer-to-array-array-of-pointers-disambiguation) and [Pointer vs array in C, non-trivial difference](http://stackoverflow.com/questions/660752/pointer-vs-array-in-c-non-trivial-difference). –  Oct 11 '13 at 19:30
  • 1
    Just for the sake of completeness there's also `char (*p)[]` which is a pointer to array of char. – aragaer Oct 11 '13 at 19:34

3 Answers3

17

Normal Declarations (Not Function Parameters)

char **p; declares a pointer to a pointer to char. It reserves space for the pointer. It does not reserve any space for the pointed-to pointers or any char.

char *p[N]; declares an array of N pointers to char. It reserves space for N pointers. It does not reserve any space for any char. N must be provided explicitly or, in a definition with initializers, implicitly by letting the compiler count the initializers.

char p[M][N]; declares an array of M arrays of N char. It reserves space for MN char. There are no pointers involved. N must be provided explicitly. M must be provided explicitly or, in a definition with initializers, implicitly by letting the compiler count the initializers.

Declarations in Function Parameters

char **p declares a pointer to a pointer to char. When the function is called, space is provided for that pointer (typically on a stack or in a processor register). No space is reserved for the pointed-to-pointers or any char.

char *p[N] is adjusted to be char **p, so it is the same as above. The value of N is ignored, and N may be absent. (Some compilers may evaluate N, so, if it is an expression with side effects, such as printf("Hello, world.\n"), these effects may occur when the function is called. The C standard is unclear on this.)

char p[M][N] is adjusted to be char (*p)[N], so it is a pointer to an array of N char. The value of M is ignored, and M may be absent. N must be provided. When the function is called, space is provided for the pointer (typically on a stack or in a processor register). No space is reserved for the array of N char.

argv

argv is created by the special software that calls main. It is filled with data that the software obtains from the “environment”. You are allowed to modify the char data in it.

In your definition char *p = "some string";, you are not permitted to modify the data that p points to because the C standard says that characters in a string literal may not be modified. (Technically, what it says is that it does not define the behavior if you try.) In this definition, p is not an array; it is a pointer to the first char in an array, and those char are inside a string literal, and you are not permitted to modify the contents of a string literal.

In your definition char p[] = "some string";, you may modify the contents of p. They are not a string literal. In this case, the string literal effectively does not exist at run-time; it is only something used to specify how the array p is initialized. Once p is initialized, you may modify it.

The data set up for argv is set up in a way that allows you to modify it (because the C standard specifies this).

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • I think that's the clearest discussion of this mess I've ever read. – Hot Licks Oct 11 '13 at 19:52
  • just an addition n in the second case (char *p[N]) and m in the third case (char p[M][N]) need not be provided when we are initializing the array with some values. – programer8 Nov 04 '13 at 01:10
6

Some more differences description looking it from memory addressing view as follows,

I. char **p; p is double pointer of type char

Declaration:

char a = 'g';
char *b = &a;
char **p = &b;


   p                    b                    a     
+------+             +------+             +------+
|      |             |      |             |      |              
|0x2000|------------>|0x1000|------------>|   g  | 
|      |             |      |             |      |
+------+             +------+             +------+
 0x3000               0x2000               0x1000
Figure 1: Typical memory layout assumption   

In above declaration, a is char type containing a character g. Pointer b contains the address of an existing character variable a. Now b is address 0x1000 and *b is character g. Finally address of b is assigned to p, therefore a is a character variable, b is pointer and p is pointer to pointer. Which implies a contains value, b contains address and p contains address of address as shown below in the diagram.

Here, sizeof(p) = sizeof(char *) on respective system;

II. char *p[M]; p is array of strings

Declaration:

char *p[] = {"Monday", "Tuesday", "Wednesday"};


      p
   +------+  
   | p[0] |       +----------+
0  | 0x100|------>| Monday\0 |              
   |      |       +----------+
   |------|       0x100
   | p[1] |       +-----------+
1  | 0x200|------>| Tuesday\0 |
   |      |       +-----------+
   |------|       0x200
   | p[2] |       +-------------+
2  | 0x300|------>| Wednesday\0 |
   |      |       +-------------+ 
   +------+       0x300
Figure 2: Typical memory layout assumption

In this declaration, p is array of 3 pointers of type char. Implies array p can hold 3 strings. Each string (Monday, Tuesday & Wednesday) is located some where in memory (0x100, 0x200 & 0x300), there addresses are in array p as (p[0], p[1] & p[2]) respectively. Hence it is array of pointers.

Notes: char *p[3];

1. p[0], p[1] & p[2] are addresses of strings of type `char *`.
2. p, p+1 & p+2 are address of address with type being `char **`.
3. Accessing elements is through, p[i][j] is char; p[i] is char *; & p is char **

Here sizeof(p) = Number of char array * sizeof(char *)

III. char p[M][N]; p is array of fixed length strings with dimensions as M x N

Declaration:

char p[][10] = {Monday, Tuesday, Wednesday};


  p  0x1 2 3 4 5 6 7  8  9  10
    +-------------------------+
 0  | M  o n d a y \0 \0 \0 \0|     
 1  | T  u e s d a  y \0 \0 \0| 
 2  | W  e d n e s  d  a  y \0|
    +-------------------------+
 Figure 3: Typical memory layout assumption

In this case array p contain 3 strings each containing 10 characters. Form the memory layout we can say p is a two dimensional array of characters with size MxN, which is 3x10 in our example. This is useful for representing strings of equal length since there is a possibility of memory wastage when strings contains lesser than 10 characters compared to declaration char *p[], which has no memory wastage because string length is not specified and it is useful for representing strings of unequal length.

Accessing elements is similar as above case, p[M] is M'th string & p[M][N] is N'th character of M'th string. Here sizeof(p) = (M rows * N columns) * sizeof(char) of two dimensional array;

Sunil Bojanapally
  • 12,528
  • 4
  • 33
  • 46
  • thanks!that was a very detailed explanation.i just want to confirm one more thing.can we change the individual characters in an array of character pointers? here is the code http://codepad.org/2vyx2IbY.it gave me a seg fault on emacs – programer8 Nov 07 '13 at 02:29
  • @programer8 Answer is No. In your code `p[i]` & `f` are pointing to constant string literals which cannot be modified assigning `p[i][j] = 'j'` & `f[i] = 'j'` respectively. Look at this [code](http://codepad.org/U8S3Velk) which tells a 2D array & a character array indeed allows you to modify the characters. – Sunil Bojanapally Nov 07 '13 at 09:09
0
  • a in char* a is pointer to array of chars, a can be modified.
  • b in char b[] is array of chars. b cannot be modified.

They are sort of compatible - b can automatically decay to a in assignments and expressions, but not other way around.

When you use char** p, char* p[] and char p[][] it is very similar situation, just more levels of indirection.

mvp
  • 111,019
  • 13
  • 122
  • 148
  • `char p[][]` is illegal, for obvious reasons. It has to be something like `char p[][6]`. – Dietrich Epp Oct 11 '13 at 19:09
  • @DietrichEpp i noticed that too.we have to mention second dimension while passing values to a function.But i was talking about command line arguments. – programer8 Oct 11 '13 at 19:17
  • @programer8: Command line arguments? What does that have to do with it? `char p[][]` is always illegal. – Dietrich Epp Oct 11 '13 at 19:20