Difference between char **p,char *p[],char p[][] - c

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?

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 M•N 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).

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;

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.

Related

Comparison of Pointer to String , Array of Characters and Pointer to Array of Characters [duplicate]

This question already has answers here:
What is the difference between char s[] and char *s?
(14 answers)
String literals: pointer vs. char array
(1 answer)
Closed 1 year ago.
This post was edited and submitted for review 1 year ago and failed to reopen the post:
Original close reason(s) were not resolved
hello to all programmers, I can't understand something
char a[]="hello"
char* b="salam"
the first question is why can't we modify 2,for example b[0]='m', I know that 2 gets stored as compile time constant BUT I can't understand what does it mean and what is the quiddity of 2 ?
and second question:
3.
char a[]="hello";
char* c=a;
c[0]='r';
Now we can modify and then print c, but we couldn't modify 2 ! why?
I can't understand the concept of those pointers please explain it to me
char a[] = "hello;" is a null terminated array of characters, the array will be initialized with the charaters you specify and the size of it will be deduced by the compiler, in this case it will have space for 6 characters, these are mutable, the charaters are copied to the array, you can change them at will. e.g. a[0] = 'x' will change hello to xello.
char* c = a; just makes the pointer c point to a, the same operations can be performed in c as you are really operating in a.
char* b = "salam" is a different animal, b is a pointer to a string literal, these are not meant to be modified, they don't get stored in an array like a, they are read only and are usually stored in some read only section of memory, either way the behavior of editing b is undefined, i.e. b[0] = 'x' is illegal as per the language rules.
char a[]="hello";
This creates an array like this:
+---+---+---+---+---+----+
a: | h | e | l | l | o | \0 |
+---+---+---+---+---+----+
The array is modifiable and you can write other characters to it later if you like (although you cannot write more than 5 or 6 of them).
char* b="salam";
This uses a string literal to create a constant string somewhere, that variable b is then a pointer to. I like to draw it like this:
+-------+
b: | * |
+---|---+
|
V
+---+---+---+---+---+----+
| s | a | l | a | m | \0 |
+---+---+---+---+---+----+
There are two differences here: (1) b is a pointer, not an array as a was. (2) the string here (that b points to) is probably in nonwritable memory. But a was definitely in writable memory.
char* c=a;
Now c is a pointer, pointing at the earlier-declared array a. The picture looks like this:
+---+---+---+---+---+----+
a: | h | e | l | l | o | \0 |
+---+---+---+---+---+----+
^
|
\
|
+---|---+
c: | * |
+-------+
And the array a was modifiable, so there's no problem doing c[0] = 'r', and we end up sounding like Scooby-Doo and saying:
+---+---+---+---+---+----+
a: | r | e | l | l | o | \0 |
+---+---+---+---+---+----+
^
|
\
|
+---|---+
c: | * |
+-------+
The key difference (which can be quite subtle) is that a string literal in source code like "hello" can be used in two very different ways. When you say
char a[] = "hello";
the string literal is used as the initial value of the array a. But the array a is an ordinary, modifiable array, and there's no problem writing to it later.
Most other uses of string literals, however, work differently. When you say
char *b = "salam";
or
printf("goodbye\n");
those string literals are used to create and initialize "anonymous" string arrays somewhere, which are referred to thereafter via pointers. The arrays are "anonymous" in that they don't have names (identifiers) to refer to them, and they're also usually placed in read-only memory, so you're not supposed to try to write to them.
Let's start of with your first question:
We have 2 strings, a and b
char a[] = "hello";
char *b = "salam";
The first string can be modified, this is because it uses a different memory segment than the second string. It is stored in the data segment of the program, and we have write access to the data segment so we can modify it.
The second string is a pointer to a string, we cannot modify string literals (pointers to strings) since c specifies that this is undefined behavior.
The address of b will just point to somewhere in the program where that string is stored. This string should preferably be declared const since it can't be modified anyways.
const char *b = "salam";
Now let's look at the second question:
The code you provided for the second question is perfectly valid,
char a[] = "hello";
char *c = a;,
c[0] = 'r';
We have a, which stores the actual string and if using ASCII it consists of 6 bytes 'h', 'e', 'l', 'l', 'o', '\0'
c points to a we can verify this with this code
#include <stdio.h>
int main(void) {
char a[] = "hello";
char *c = a;
c[0] = 'r';
printf("a: %p\nc: %p\n", &a, &*c);
}
And we'll get output as such
a: 0x7ffe3c94ecf2
c: 0x7ffe3c94ecf2
They both point to the same address, the start of the array when we do
c[0] // It essentially means *(c + 0) = in other words the address which c points to + 0 and then we subscript this is how subscripting works a[1] = *(a + 1), etc...
So pretty much c in this case points to
0x7ffe3c94ecf2
c + 0 =
0x7ffe3c94ecf2
Access that address and modify the character.

Understanding the dereference, address-of, and array subscript operators in C

I have argv[] defined as a char *. Using the following printf statements:
printf("%s\n",argv[1]); // prints out the entire string
printf("%p\n",&argv[1]); // & -> gets the address
printf("%c\n",argv[1][0]);// prints out the first char of second var
printf("%c\n",*argv[1]); //
It's this last one I don't understand. What does it mean to print *argv[1]? why isn't that the same as *argv[1][0] and how come you can't print out printf("%s\n",*argv[1]);. Also, why is &*argv[1] a different address then &argv[1]?
The array subscript operation a[i] is defined as *(a + i) - given the address a, offset i elements (not bytes) from that address and dereference the result. Thus, given a pointer p, *p is equivalent to *(p + 0), which is equivalent to p[0].
The type of argv is char **; given that, all of the following are true:
Expression Type Value
---------- ---- -----
argv char ** Pointer to a sequence of strings
*argv char * Equivalent to argv[0]
**argv char Equivalent to argv[0][0]
argv[i] char * Pointer to a single string
*argv[i] char Same as argv[i][0]
argv[i][j] char j'th character of i'th string
&argv[i] char ** Address of the pointer to the i'th string
Since the type of argv[i][j] is char, *argv[i][j] is not a valid expression.
Here's a bad visualization of the argv sequence:
+---+ +---+ +---+
argv | | ---> argv[0] | | ---------------------------> argv[0][0] | |
+---+ +---+ +---+ +---+
argv[1] | | -------> argv[1][0] | | argv[0][1] | |
+---+ +---+ +---+
... argv[1][1] | | ...
+---+ +---+ +---+
argv[argc] | | ---||| ... argv[0][n-1] | |
+---+ +---+ +---+
argv[1][m-1] | |
+---+
This may help explain the results of different expressions.
char *argv[]
argv is array(1) of char pointers. So it is normal array just each element of the array is a pointer. argv[0] is a pointer, argv[1], etc.
argv[0] - first element in the array. Since each element in the array is char pointer, value of this is also a char pointer (as we already mentioned above).
*argv[1] - Now here argv[1] is second element in the above array, but argv[1] is also a char pointer. Applying * just dereferences the pointer and you get the first character in the string to which argv[1] points to.
You should use %c to print it as this is just a character.
argv[1][0] is already first character of second string in the array - so no more room for dereferencing. This is essentially same as previous.
(1) as highlighted strictly saying it is pointer to pointer, but maybe you can "think" of it as array of pointers. Anyway more info about it here: https://stackoverflow.com/a/39096006/3963067
If argv[1] is a pointer to char, then *argv[1] dereferences that pointer and gets you the first character of the string at argv[1], so it's the same as argv[1][0] and is printed with the "%c" format specifier.
argv[1][0] is a char itself, not a pointer, so it's not dereferensable.
This is not specific to char *.
You can simplify by what is the difference between *ptr and ptr[0].
There are no difference because ptr[0] is a sugar for *(ptr + 0) or *ptr because + 0 is useless.
// printf("%p\n", &argv[1]); is wrong you must cast to (void *)
printf("%p\n", (void *)&argv[1]);
Because %p specifier expect a void *, in normal case C auto promote your pointer into void * but printf() use variable argument list. There are a lot of rule about this, I let you read the doc if you want. But char * wiil not be promote to void * and like I say printf() except void * so you have a undefined behavior if you don't cast it yourself.
The last line printf("%c\n",*argv[1]); is both dereferencing argv and accessing array index 1. In other words, this is doing argv[1][0], just like the previous line, because the array subscript access [1] has a higher precedence than the dereference operator (*).
However, if you were to parenthesize the expression in the last line to make the dereference operator be processed first, you would do this:
printf("%c\n", (*argv)[1]);
Now, when you run the program, the last line of output would be argv[0][1] instead of [1][0], i.e. the second character in the command line you use to execute the program.

What's the difference between the types - int * and int *[100] in C?

Kinda of a noob so don't kill me here.
What's the difference between the following codes?
int *p; //As i understand, it creates a pointer to an variable of size int.
int *p[100]; //Don't really know what this is.
int (*p)[100]; // I have come to understand that this is a pointer to an array.
This is a pointer to an int:
int *p;
┌────┐
│int*│
└────┘
It should point at an int, something like this:
┌────┐
│int*│
└─┃──┘
▼
┌───┐
│int│
└───┘
This is an array of 100 pointers to int:
int *p[100];
That is, it gives you 100 pointers.
┌────┬────┬────┬────┬────┬────┬┄
│int*│int*│int*│int*│int*│int*│
└────┴────┴────┴────┴────┴────┴┄
Each pointer should point an int, perhaps like this:
┌────┬────┬────┬────┬────┬────┬┄
│int*│int*│int*│int*│int*│int*│
└─┃──┴─┃──┴─┃──┴─┃──┴─┃──┴─┃──┴┄
▼ ▼ ▼ ▼ ▼ ▼
┌───┐┌───┐┌───┐┌───┐┌───┐┌───┐┌┄
│int││int││int││int││int││int││
└───┘└───┘└───┘└───┘└───┘└───┘└┄
Of course, there's no reason they can't all point at the same int, or whatever.
You may want to use an array of pointers if you want many pointers that you can easily
iterate over. You may, for example, dynamically allocate objects and have each pointer point at a different object:
p[0] = new int(0);
p[1] = new int(0);
// ...
Perhaps dynamically allocating ints isn't the best example, but I think the point is clear.
This is a pointer to an array of 100 int:
int (*p)[100];
That is, it gives you just 1 pointer:
┌───────────┐
│int(*)[100]│
└───────────┘
It should point at an array that contains 100 ints:
┌───────────┐
│int(*)[100]│
└─┃─────────┘
▼
┌───┬───┬───┬───┬───┬───┬┄
│int│int│int│int│int│int│
└───┴───┴───┴───┴───┴───┴┄
You will get a pointer to an array when you use the address-of operator (&) on the name of an array. For example:
int arr[100] = { /* some initial values */ };
int (*p)[100] = &arr;
Here, I've taken the address of the arr array, which gives me a pointer to that array. If you then want to access an element of the array, you have to dereference the pointer first: (*p)[3] will access element 3.
Side note:
Always remember that arrays are not pointers. As we have just seen, we can take the address of an array to get a pointer to it, just like any other (non-temporary) object in C++. The only special connection between arrays and pointers is that the name of an array can be implicitly converted to a pointer to the array's first element. That means the following is valid:
int arr[100] = { /* some initial values */ };
int* p = arr;
The pointer p will point at the first element in arr. Note that p is not a pointer to the array, but a pointer to an element of the array.
(Also note that there is no such thing as an array type function argument. If you write something like int p[] as a function argument, it is transformed by the compiler to be a int*.)
Sounds like you could use an introduction to the Spiral Rule.
Start at the variable and "spiral" your way around right to left:
+-------+
| +--+ | // So we have:
| | | | p // p
int * p | | * p // p is a pointer
^ ^ | | int * p // p is a pointer to an int
| +----+ |
+----------+
Next one:
+--------+
| +--+ | p // p
| | V | p[100] // p is an array of 100
int * p[100] | * p[100] // p is an array of 100 pointers
^ ^ | | int * p[100] // p is an array of 100 pointers to ints
| +----+ |
+-----------+
Finally, a new part of the rule, do anything in parenthesis first:
+-----+
| +-+ |
| ^ | | ( p) // p
int (* p) [100]; (*p) // p is a pointer
^ ^ | | (*p)[100] // p is a pointer to an array of 100
| +---+ | int (*p)[100] // p is a pointer to an array of 100 ints
+---------+
If you're online/have access to a computer, it's always usefule to use the cdecl.org site, but it's important to be able to read code offline as well, and this rule will let you do just that.
Kinda of a noob so don't kill me here
Working out what a type means in C can be tricky even for experts. No worries.
What's the difference between the following codes?
The other answers are good and I have no intention of contradicting them. Rather, here's yet another way to think about it. We need to define three things:
A variable is a thing that supports three operations. The fetch operation takes a variable and produces its current value. The fetch operation has no notation; you simply use the variable. The store operation takes a variable and a value, and stores the value in the variable. The address operation takes a variable and produces a pointer.
A pointer is a thing that supports one operation. The dereference operation, written as prefix *pointer, takes a pointer and produces a variable. (Pointers support other operations such as arithmetic and indexing -- which is a form of arithmetic -- but let's not go there.)
An array is a thing that supports one operation. The index operation takes an array and an integer and produces a variable. It's syntax is postfix: array[index]
OK, so now we come to your question. What does the declaration
int p;
mean? That the expression p is a variable of type int. Note that this is a variable; you can store things to p. What does the declaration
int *p;
mean? That the expression *p is a variable of type int. Now that we know that we can deduce what p is. Since *p is a dereference and produces a variable, p must be a pointer to int. What does the declaration
int *p[100];
mean? It means that *the expression *p[i] is a variable of type int provided that i is an integer value from 0 to 99. We got a variable out, but we could have gotten there from either the pointer or the array, so we have to figure out which. We consult the operator precedence table and discover that the indexing operator binds "tighter" than the dereferencing operator. That is:
*p[i]
is the same thing as
*(p[i])
and remember, that thing is a variable of type int. The contents of the parens are dereferenced to produce a variable of type int so the contents of the parens must be a pointer to int. Therefore
p[i]
is a pointer to int. How is that possible? This must be a fetch of a variable of type pointer-to-int! So p[i] is a variable of type pointer to int. Since this is an index operation, p must be an array of pointers to int.
Now you do the next one.
int (*p)[100];
means what?
int *p; --> Declares a pointer to an integer type.
int *p[100]; -->Declares an array of 100 pointers to integer type.
int (*p)[100]; --> Declares a pointer to an array of 100 integers.
Use cdecl for translating such types.

Pointer to pointer gives segmentation fault?

Here is the code
int main
{
char s[]="prady";
char **p;
p=(char **)&s;
printf("%u %u\n",p,*p);
printf("%u %u\n",&s,s);
printf("%s\n",s);
printf("%s\n",&s);
printf("%u %u\n",s+1,&s+1);
printf("%s\n",p);
printf("%s\n",*p);
}
o/p:
3217062327 1684107888
3217062327 3217062327
prady
prady
3217062328 3217062336
prady
Segmentation fault
My doubt as follows
How both the address is same of s and &s?
If both are same then how they show different when adding 1 to it?
How I got segmentation fault in *p?
First, arrays are not pointers. Pointers are not arrays. Arrays decay into pointers.
1.How both the address is same of s and &s?
char s[]="prady";
--------------------------
s: | p | r | a | d | y | \0 |
--------------------------
The array s is a request for 6 characters to be set aside. In other words, at s there are 6 characters. 's` is a "thing", it doesn't point at anything, it just is.
char *ptr = "prady";
------ --------------------------
|*ptr| --> | p | r | a | d | y | \0 |
------ --------------------------
The pointer ptr requests a place which holds a pointer. The pointer can point at any char or any string literal (continuous chars).
Another way to think about this:
int b; //this is integer type
&b; //this is the address of the int b, right?
int c[]; //this is the array of ints
&c; //this would be the address of the array, right?
So that's pretty understandable how about this:
*c; //that's the first element in the array
What does that line of code tell you? if I deference c, then I get an int. That means just plain c is an address. Since it's the start of the array it's the address of the array, thus:
c == &c;
2. If both are same then how they show different when adding 1 to it.
From my answer to #1 I assume you see why they're not the same. So why do you get different values?
Look at the values you get:
s = 0x3217062327
s+1 = 0x3217062328 // It's 1 bigger, why? Because a char takes 1 byte, s holds chars
// so s (address of a char) + 1 (sizeof char) gives you one more than s
&a + 1 //This is adding 1 (sizeof array) which is bigger than the size of a char
3. How I got segmentation fault in *p.
I think you can get this from my previous two answers...
But:
p is a pointer to a pointer to a character
You set p to the address of the array (which remember, is the array itself)
a deference of p is a pointer to a char (another address), however you can't do that to the array.
When you typecast you tell the compiler "I know better then you so just make these two work". When you segfault... it's because you didn't really know better.
In your case s isn't a pointer. It is an array!
a small change will fix a thing:
char *s = "prady";
1.How both the address is same of s and &s.
s is an array of characters. But, arrays are converted to pointers, save in a few cases: when they are used to initialize an array (e.g: your char s[]="prady";
line), when they are the operand of the unary & operator (plenty of cases in your code), and when they are the operand of the sizeof operator.
2.If both are same then how they show different when adding 1 to it.
They are not the same.
2.How I got segmentation fault in *p.
p contains the address of "prady". *p contains "prady". Attempting to use "prady" as if it were the address of a string causes a segfault.

Difference between char a[]="string"; char *p="string"; [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicates:
What is the difference between char s[] and char *s in C?
What is the difference between char a[]="string"; and char *p="string";?
The first one is array the other is pointer.
The array declaration "char a[6];" requests that space for six characters be set aside, to be known by the name "a." That is, there is a location named "a" at which six characters can sit. The pointer declaration "char *p;" on the other hand, requests a place which holds a pointer. The pointer is to be known by the name "p," and can point to any char (or contiguous array of chars) anywhere.
The statements
char a[] = "hello";
char *p = "world";
would result in data structures which could be represented like this:
+---+---+---+---+---+---+
a: | h | e | l | l | o |\0 |
+---+---+---+---+---+---+
+-----+ +---+---+---+---+---+---+
p: | *======> | w | o | r | l | d |\0 |
+-----+ +---+---+---+---+---+---+
It is important to realize that a reference like x[3] generates different code depending on whether x is an array or a pointer. Given the declarations above, when the compiler sees the expression a[3], it emits code to start at the location "a," move three past it, and fetch the character there. When it sees the expression p[3], it emits code to start at the location "p," fetch the pointer value there, add three to the pointer, and finally fetch the character pointed to. In the example above, both a[3] and p[3] happen to be the character 'l', but the compiler gets there differently.
You can use search there are tons of explanations on the subject in th internet.
char a[]="string"; //a is an array of characters.
char *p="string";// p is a string literal having static allocation. Any attempt to modify contents of p leads to Undefined Behavior since string literals are stored in read-only section of memory.
No difference. Unless you want to actually write to the array, in which case the whole world will explode if you try to use the second form. See here.
First declaration declares an array, while second - a pointer.
If you're interested in difference in some particular aspect, please clarify your question.
One difference is that sizeof(a)-1 will be replaced with the length of the string at compile time. With p you need to use strlen(p) to get the length at runtime. Also some compilers don't like char *p="string", they want const char *p="string" in which case the memory for "string" is read-only but the memory for a is not. Even if the compiler does not require the const declaration it's bad practice to modify the string pointed to by p (ie *p='a'). The pointer p can be changed to point to something else. With the array a, a new value has to be copied into the array (if it fits).

Resources