I am working with C and I'm a bit rusty. I am aware that * has three uses:
Declaring a pointer.
Dereferencing a pointer.
Multiplication
However, what does it mean when there are two asterisks (**) before a variable declaration:
char **aPointer = ...
Thanks,
Scott
It declares a pointer to a char pointer.
The usage of such a pointer would be to do such things like:
void setCharPointerToX(char ** character) {
*character = "x"; //using the dereference operator (*) to get the value that character points to (in this case a char pointer
}
char *y;
setCharPointerToX(&y); //using the address-of (&) operator here
printf("%s", y); //x
Here's another example:
char *original = "awesomeness";
char **pointer_to_original = &original;
(*pointer_to_original) = "is awesome";
printf("%s", original); //is awesome
Use of ** with arrays:
char** array = malloc(sizeof(*array) * 2); //2 elements
(*array) = "Hey"; //equivalent to array[0]
*(array + 1) = "There"; //array[1]
printf("%s", array[1]); //outputs There
The [] operator on arrays does essentially pointer arithmetic on the front pointer, so, the way array[1] would be evaluated is as follows:
array[1] == *(array + 1);
This is one of the reasons why array indices start from 0, because:
array[0] == *(array + 0) == *(array);
C and C++ allows the use of pointers that point to pointers (say that five times fast). Take a look at the following code:
char a;
char *b;
char **c;
a = 'Z';
b = &a; // read as "address of a"
c = &b; // read as "address of b"
The variable a holds a character. The variable b points to a location in memory that contains a character. The variable c points to a location in memory that contains a pointer that points to a location in memory that contains a character.
Suppose that the variable a stores its data at address 1000 (BEWARE: example memory locations are totally made up). Suppose that the variable b stores its data at address 2000, and that the variable c stores its data at address 3000. Given all of this, we have the following memory layout:
MEMORY LOCATION 1000 (variable a): 'Z'
MEMORY LOCATION 2000 (variable b): 1000 <--- points to memory location 1000
MEMORY LOCATION 3000 (variable c): 2000 <--- points to memory location 2000
It declares aPointer as a pointer to a pointer to char.
Declarations in C are centered around the types of expressions; the common name for it is "declaration mimics use". As a simple example, suppose we have a pointer to int named p and we want to access the integer value it's currently pointing to. We would dereference the pointer with the unary * operator, like so:
x = *p;
The type of the expression *p is int, so the declaration of the pointer variable p is
int *p;
In this case, aPointer is a pointer to a pointer to char; if we want to get to the character value it's currently pointing to, we would have to dereference it twice:
c = **aPointer;
So, going by the logic above, the declaration of the pointer variable aPointer is
char **aPointer;
because the type of the expression **aPointer is char.
Why would you ever have a pointer to a pointer? It shows up in several contexts:
You want a function to modify a pointer value; one example is the strtol library function, whose prototype (as of C99) is
long strtol(const char * restrict str, char ** restrict ptr, int base);
The second argument is a pointer to a pointer to char; when you call strtol, you pass the address of a pointer to char as the second argument, and after the call it will point to the first character in the string that wasn't converted.
Remember that in most contexts, an expression of type "N-element array of T" is implicitly converted to type "pointer to T", and its value is the address of the first element of the array. If "T" is "pointer to char", then an expression of type "N-element array of pointer to char" will be converted to "pointer to pointer to char". For example:
void foo(char **arr)
{
size_t i = 0;
for (i = 0; arr[i] != NULL; i++)
printf("%s\n", arr[i]);
}
void bar(void)
{
char *ptrs[N] = {"foo", "bar", "bletch", NULL};
foo(ptrs); // ptrs decays from char *[N] to char **
}
You want to dynamically allocate a multi-dimensional array:
#define ROWS ...
#define COLS ...
...
char **arr = malloc(sizeof *arr * ROWS);
if (arr)
{
size_t i;
for (i = 0; i < ROWS; i++)
{
arr[i] = malloc(sizeof *arr[i] * COLS);
if (arr[i])
{
size_t j;
for (j = 0; j < COLS; j++)
{
arr[i][j] = ...;
}
}
}
}
It means that aPointer points to a char pointer.
So
aPointer: pointer to char pointer
*aPointer :pointer to char
**aPointer: char
An example of its usage is creating a dynamic array of c strings
char **aPointer = (char**) malloc(num_strings);
aPointer gives you a char, which can be used to represent a zero-terminated string.
*aPointer = (char*)malloc( string_len + 1); //aPointer[0]
*(aPointer + 1) = (char*)malloc( string_len + 1); //aPointer[1]
This is a pointer to a pointer to char.
Related
Fragment 1:
char** x;
char arr[][4] = {"abc","def"};
x = arr; // why is this wrong ? but;
Fragment 2:
char* x;
char arr[4] = {"def"};
x = arr; // this is correct
So how can we assign 2d array to a double pointer (also for any multidimensional arrays)?
Also, I have a struct and I want to make an assignment as follows:
struct document
{
char **text;
int numOfLines;
};
char arr[3][50] = {
"IF WE COULD TAKE THE TIME",
"TO LAY IT ON THE LINE",
"I COULD REST MY HEAD" };
t->text = arr; // I think it is the same problem
but can we directly assign a double pointer as:
t->text = { "IF WE COULD TAKE THE TIME", "TO LAY IT ON THE LINE", "I COULD REST MY HEAD" };
Also why does this work:
char *arr[3] = {
"IF WE COULD TAKE THE TIME",
"TO LAY IT ON THE LINE",
"I COULD REST MY HEAD" };
t->text = arr;
Statement char **x; means pointer to pointer, but char arr[][4]; is somehow pointer to array.
Code below works.
#include <stdio.h>
int main(void)
{
char (*x)[10];
char arr1[][10] = {{"First"}, {"Second"}};
x = arr1;
printf("%s\n%s\n", arr1[0], arr1[1]);
printf("%s\n%s\n", x[0], x[1]);
return 0;
}
Question 1
char arr[][4] = {"abc","def"}; defines arr to be an array of arrays. With other objects, such as a structure, one structure, say C, could be assigned to another structure, say B, of the same type, using B = C;. However, C has special rules for arrays.
When an array is used in an expression, it is automatically converted to a pointer to its first element, except when it is the operand of sizeof or unary & or is a string literal used to initialize an array. So, when we write:
x = arr;
the automatic conversion makes it as if we had written:
x = &arr[0];
Then, since &arr[0] is a pointer to an array of 4 char, x must also be a pointer to an array of 4 char (or something compatible, perhaps a pointer to an array of an unknown number of char).
Note that char **x; declares a pointer to a pointer. That is, it is a pointer, and, at the memory it points to, there must be another pointer. In contrast, &arr[0] is a pointer to an array. It is a pointer, and, at the memory it points to, there is an array of 4 char. If you tried to use **x, the compiler would look at the memory that x points to and expect to find a pointer there. If, instead, there is not a pointer but rather four arbitrary char values, the program would be broken. So char **x is not compatible with a pointer to an array of 4 char.
A proper declaration for x would be char (*x)[4];. After such a declaration, the assignment x = arr; would be proper.
Question 2
Your code t->text = { "IF WE COULD TAKE THE TIME", "TO LAY IT ON THE LINE", "I COULD REST MY HEAD" }; is not strictly conforming C and does not compile in typical compilers.
Question 3
Consider the code (adjusted to allow compilation):
struct document
{
char **text;
int numOfLines;
} t;
char *arr[3] = {
"IF WE COULD TAKE THE TIME",
"TO LAY IT ON THE LINE",
"I COULD REST MY HEAD" };
t.text = arr;
char *arr[3] declares arr to be an array of 3 pointers to char. It is then initialized to contain three pointers to (the first characters of) strings.
So each element of arr, arr[i] is a pointer to char. By C’s rule about automatic conversion of arrays, in t.text = arr;, arr is converted to a pointer to its first element. So we have t.text = &arr[0];. Then &arr[0] is a pointer to a pointer to a char, and t.text is a pointer to a pointer to a char, so the types are compatible.
So I'm cruising through Learn C the Hard Way (just enrichment) - but one bonus problem I've come across is the following -
#include <stdio.h>
char * mystrcpy(char *, char *);
int main(void) {
char dest[100];
char src[] = "Test string\n";
char *p;
if (p = mystrcpy(dest,src)) {
printf("%s\n",p);
return(0);
}
else {
printf("null pointer received\n");
return(1);
}
}
/* mystrcpy: Copy a string from s to a buffer pointer to by d.
d = destination buffer
s = source string
return value = a pointer to the beginning of the string in the
destination buffer.
*/
char * mystrcpy(char *d, char *s) {
}
I know that *d and *s are both pointer variables, but I'm not exactly sure what that means, nor how to use them in the context of this problem. Any help or "pointers" (no pun intended) would be greatly appreciated.
Except when it is the operand of the sizeof or unary & operators, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T" will be adjusted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array.
In the call to mystrcpy, the expressions src and dest "decay" from type "array of char" to "pointer to char", so what the function actually receives are the pointer values corresponding to the addresses of the first element of each array.
You can access the contents of each array by using the [] subscript operator on the pointer expressions1:
d[i] = s[i];
or, you can dereference each pointer directly:
*d = *s;
and adjust the value of each pointer
d++;
s++;
Note that these operations may be combined:
*d++ = *s++;
From there it's just a matter of determining where the source string ends.
The expression a[i] is defined as *(a + i); given the pointer value a, offset i elements (not bytes!) from that address and dereference the result. This is why the array conversion rule mentioned above exists in the first place.
I wrote the following code which works, and I can see that a pointer only takes up (I think) 4 bytes of memory; while a plain old array takes up 20 bytes. However, I am not sure entirely why it works!
When I declare my character array I had to make it a pointer, otherwise it would not compile and run. I then was able to make my character an int type pointer; but I am not sure why this works.
Why can I do this "int *ptrOfChars = arrayOfChars;" and not do this "char *ptrOfChars = arrayOfChars;" ?
Here's my code:
int main(void)
{
int i;
int arrayOfNums[] = {1,2,3,4,5};
char *arrayOfChars[] = {"hello","how","are","you","doing"};
float arrayOfFloats[] = {1.23,2.34,3.45,4.56,5.67};
int *ptrOfNums = arrayOfNums;
int *ptrOfChars = arrayOfChars;
float *ptrOfFloats = arrayOfFloats;
printf("\n\n");
printf("----- Array of Numbers -----\n");
printf("The size of this array is %d\n\n", sizeof(arrayOfNums));
for (i = 0; i < 5; i++)
{
printf("Value in the array is %d\n", *ptrOfNums);
printf("Address of pointer is %x\n", ptrOfNums++);
}
printf("\n\n");
printf("----- Array of Characters -----\n");
printf("The size of this array is %d\n\n", sizeof(*arrayOfChars));
for (i = 0; i < 5; i++)
{
printf("Value in the array is %s\n", *ptrOfChars);
printf("Address of pointer is %x\n", ptrOfChars++);
}
printf("\n\n");
printf("----- Mardi Gras -----\n");
printf("The size of this array is %d\n\n", sizeof(arrayOfFloats));
for (i = 0; i < 5; i++)
{
printf("Value in the array is %f\n", *ptrOfFloats);
printf("Address of pointer is %x\n", ptrOfFloats++);
}
system("pause");
return 0;
}
Thanks for your assistance!!
//This is an array of strings.
char *arrayOfChars[]={"hello","how","are","you","doing"};
//This is an array of characters.
char arrayOfChars[]={'h','e','l','l','o',};
Each pointer in your array char *arrayOfChars[] , points to the first character of each word.
This is all the information you need to find a word from your array.
For example to get the first word of your array you need a pointer to the first character of the string 'hello'.
Then you will find the next character and the next and so on.
h --> e --> l --> l --> o --> EndOfString.
You declares a array of pointer which is of (char *) type.
char *arrayOfChars[] = {"hello","how","are","you","doing"};
which means you have:
arrayOfChars[0] -> "hello"
arrayOfChars[1] -> "how"
arrayOfChars[2] -> "are"
arrayOfChars[3] -> "you"
arrayOfChars[4] -> "doing"
And the sizeof(arrayOfChars[0]) is 4 (4 bytes, this is the size of char * variable), the strlen(arrayOfChars[0]) is 5 (the length of the string "hello"). Hope it helps.
arrayOfChars is not a array of characters but an array of pointers to strings. Therefore, the correct definition for ptrOfChars should be:
char **ptrOfChars = arrayOfChars;
Assigning arrayOfChars to int *ptrOfChars works because in this case, the size of a pointer and of an int are both 4 bytes and therefore are identical in size. Furthermore, because C doesn't really do any strong type checking, passing the value of int as the value of a char pointer still works correctly. However, under a different memory model such as 64 bit, the size of both the pointer and of an int could be different and therefore your code wouldn't work with int *ptrOfChars.
To print the size of the array arrayOfChars, you need to use sizeof(arrayOfChars) instead of sizeof(*arrayOfChars).
Finally, the type for the values for 1.23, 2.34, etc. is double and not float. To have float, you should add a little f at the end: 1.23f, 2.34f, etc.
it is because when you will print the value of arrayOfChars it is an integer(an address of arrayOfChars[0] i.e"Hello").
and your ptrOfChars is pointing to this integer.
Why can I do this "int *ptrOfChars = arrayOfChars;" and not do this "char *ptrOfChars = arrayOfChars;" ?
Because the type of the expression arrayOfChars "decays" to type char **, not char *.
Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression is the address of the first element of the array.
So, given the declaration:
char *arrayOfChars[] = {"hello","how","are","you","doing"};
the expression arrayOfChars has type "5-element array of char *" (each of the string literals is also an array expression, and also subject to the conversion rule mentioned above). If arrayOfChars appears in an expression where it is not the operand of the sizeof or unary * operators, it will be converted to an expression of type "pointer to char *", or char **.
I would have expected the compiler to complain about initializing an int * with a char ** expression.
Finally, use the %p conversion specifier to print out pointer values:
printf( "address of arrayOfChars = %p\n", (void *) arrayOfChars );
This is one of the few places where an explicit cast to void * is needed.
I was reading through some lecture notes that in order for a pointer to reference a 2D array, it has to be given the address of the first element.
int a[10][10];
int *p = &a[0][0];
I've never tried this, so I was curious why isn't it enough to assign the array itself to the pointer, just as we do in a 1D case.
int a[10][10];
int *p = a;
The array is kept in an uninterrupted 'line' of memory anyway, and 2D arrays only have a different type, but the same structure as 1D arrays.
By doing this
int *p = &a[0][0];
I don't see how we give the pointer any more information than by doing this
int *p = a;
Or maybe all arrays regardless of their number of dimensions have the same type, the only difference being that multidimensional arrays store their extra dimensions before their first element and we need to jump over those memory spaces which remember sizes of an array's dimensions?
First, some background:
Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array.
Given the declaration
int a[10][10];
the expression a has type "10-element array of 10-element array of int". Unless this expression is the operand of the sizeof or unary & operators, it will be converted to an expression of type "pointer to 10-element array of int", or int (*)[10].
Given that declaration, all of the following are true:
Expression Type Decays to
---------- ---- ---------
a int [10][10] int (*)[10]
&a int (*)[10][10]
*a int [10] int *
a[i] int [10] int *
&a[i] int (*)[10]
*a[i] int
a[i][j] int
&a[i][j] int *
Also,
sizeof a == sizeof (int) * 10 * 10
sizeof &a == sizeof (int (*)[10][10])
sizeof *a == sizeof (int) * 10
sizeof a[i] == sizeof (int) * 10
sizeof &a[i] == sizeof (int (*)[10] )
sizeof *a[i] == sizeif (int)
sizeof a[i][j] == sizeof (int)
sizeof &a[i][j] == sizeof (int *)
Note that the different pointer types int (*)[10][10], int (*)[10], and int * don't have to be the same size or have the same representation, although on the platforms I'm familiar with they do.
The address of the first element of the array is the same as the address of the array itself; thus, all of a, &a, a[0], &a[0], and &a[0][0] will yield the same value, but the types will be different (as shown in the table above).
So, assume we add the following declarations:
int *p0 = &a[0][0]; // equivalent to int *p0 = a[0];
int (*p1)[10] = &a[0]; // equivalent to int (*p1)[10] = a;
int (*p2)[10][10] = &a;
All of p0, p1, and p2 initially have the same value, which is the address of the first element in a; however, because of the different pointer types, the results operations involving pointer arithmetic will be different. The expression p0 + 1 will yield the address of the next int object (&a[0][1]). The expression p1 + 1 will yield the address of the next 10-element array of int (&a[1][0]). And finally, the expression p2 + 1 will yield the address of the next 10-element array of 10-element array of int (effectively, &a[11][0]).
Note the types of p1 and p2; neither is a simple int *, because the expressions being used to initialize them are not that type (refer to the first table).
Note the pattern; for an array type, the simpler the expression, the more complicated the corresponding type will be. The expression a does not refer to a single int object; it refers to a 10x10 array of int objects, so when it appears in an expression, it is treated as a pointer to an array of integers, not a pointer to a single integer.
The compiler knows that "a" is a pointer to ten integers. If you don't declare the dimensions, then the compiler sees the new pointer as a pointer to an unknown number of integers. This will work in your case, but it will generate a compiler warning because the compiler sees them as incompatible pointers. The syntax for what you are trying to do (without generating a compiler warning) is:
int a[10][10];
int *p1 = &a[0][0];
int (*p2)[10] = a;
printf("p1: %p p2: %p\n", p1, p2);
One reason this is important is pointer arithmetic:
p1++; //move forward sizeof(int) bytes
p2++; //move forward sizeof(int) * 10 bytes
You understanding is close, the difference is the type information. Pointer does has its type. For example int* p, the pointer type is int*, as int a[10][10], the corresponding pointer type is int *[10][10].
In your example, p and a do point to the same address, but they're different type, which matters when perform arithmetic operation on them.
Here's an example from this URL
Suppose now that we define three pointers :
char *mychar;
short *myshort;
long *mylong;
and that we know that they point to the memory locations 1000, 2000, and 3000, respectively.
Therefore, if we write:
++mychar;
++myshort;
++mylong;
mychar, as one would expect, would contain the value 1001. But not so obviously, myshort would contain the value 2002, and mylong would contain 3004, even though they have each been incremented only once. The reason is that, when adding one to a pointer, the pointer is made to point to the following element of the same type, and, therefore, the size in bytes of the type it points to is added to the pointer.
You are right, you can assign the array itself to the pointer:
int a[10][10] = {[0][0]=6,[0][1]=1,[1][0]=10,[1][1]=11};
int b[10][10][10] = {[0][0][0]=8,[0][0][1]=1,[0][1][0]=10,[1][0][0]=100};
int *p, *q, *r, *s;
p = &a[0][0];
q = a; // what you are saying
r = &b[0][0][0];
s = b; // what you are saying
printf("p= %p,*p= %d\n",p,*p);
printf("q= %p,*q= %d\n",q,*q);
printf("r= %p,*r= %d\n",r,*r);
printf("s= %p,*s= %d\n",s,*s);
And the output is:
p= 0xbfdd2eb0,*p= 6
q= 0xbfdd2eb0,*q= 6
r= 0xbfdd3040,*r= 8
s= 0xbfdd3040,*s= 8
They point to the same address, regardless of the dimension of the matrix. So, what you are saying is right.
Well in 2D array, the outcome of *a and a is the same, they all point to the first address of this 2D array!
But if you want to define a pointer to point to this array, you could use int (*ptr)[10] for example.
You are right, 1D and 2D share the same structure, but 2D has some additional manipulation on pointers like above.
So all in all, in 2D array, a, *a and &a[0][0] prints the same address, but their usages may vary.
Like this:
#include<stdio.h>
int main() {
int a[10][10];
int *pa1 = &a[0][0];
int *pa2 = *a;
printf("pa1 is %p\n", pa1);
printf("pa2 is %p\n", pa2);
printf("Address of a is %p\n", a);
// pointer to array
int (*pa3)[10];
pa3 = a;
printf("pa3 is %p\n", pa3);
return 0;
}
They print the same address.
I'm trying to learn C now, I'm coming from Java and there is some stuff that is new to me.
I want to print a string and send an int and a string(char array) to another method. But I keep getting some errors that I don't know how to fix.
Would really appreciate if someone could take their time and explain to me what's wrong in my code. I'm quite disoriented at the moment with these pointers. When to use %s and %c when printing etc...
Code:
#include <stdio.h>
void main()
{
int k = 10;
char string;
char *sptr;
string = "hello!";
int *ptr;
sptr = &string;
ptr = &k;
printf("%s \n", &sptr);
printf("Sending pointer.\n");
sendptr(ptr, sptr);
}
And the errors.
test.c: In function ‘main’:
test.c:8:9: warning: assignment makes integer from pointer without a cast
test.c:15:2: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘char **’
tezt.c: In function ‘sendptr’:
tezt.c:8:8: error: incompatible types when assigning to type ‘char[6]’ from type ‘char’
Thanks for your time! :)
First functions solved.
Second function i get this..
tezt.c: In function ‘sendptr’:
tezt.c:5:2: error: invalid initializer
#include <stdio.h>
void sendptr(int *test, char *fname)
{
char fnamn[] = &fname;
int pt;
pt = *test;
printf("%p \n", test);
printf("%d \n", pt);
printf("%s \n", fnamn);
}
char string;
string = "hello!";
First problem: you're declaring string as a single char, not as an array. Also, you can only initialize the array to a string literal in a single statement.
char string[] = "hello!";
Second problem: sptr is a pointer-to-char, so it has to point to the first element of your string. Either of these will do:
char *sptr = string;
char *sptr = &string[0];
Then, when printing the string, just pass sptr directly.
printf("%s \n", sptr);
EDIT for your next question.
char fnamn[] = &fname;
You're trying to assign a char** (pointer to pointer to char) to an array. That just won't work. If you want to copy the string pointed to by fname into fnamn then you need to use a function such as strncpy.
char fnamn[MAX_STRING_SIZE];
strncpy(fnamn, fname, MAX_STRING_SIZE);
Having said that, if you just want to print the string, then print fname directly without copying it into your array first.
Here's a corrected version of the program with some annotation:
#include <stdio.h>
int main(void) // int and (void) for standard mains.
{
int k = 10;
char *string; // a C string is a char array, you need a pointer to point to it
char *sptr;
int *ptr;
string = "hello!";
sptr = string;
ptr = &k;
printf("%s \n", sptr); // no &. The %s format expects a char*.
printf("Sending pointer.\n");
// sendptr(ptr, sptr); // don't know what this function is, ignoring
return 0;
}
In C language, the & operator means you want to use the address of the variable (ie & = "the address of the variable").
int an_integer=2; // an_integer is a memory part where you want to store 2 ;)
printf("%d", &an_integer); // here you will print the address of the memory part where an_integer is stored (not 2, more something like 2510849).
The * operator in a declaration of variable means that you want to have a pointer to a memory part, when using it in the code, it means the "the value contained at the address of"
int an_integer=2;
int *ptr_integer; // you declare a pointer to an integer
ptr_integer = &an_integer; // here you set the pointer ptr_integer to the address of an_integer
printf("%d", *ptr_integer); // here you print the value contained at the memory address stored in the ptr_integer
The [] operator means you want to store an array of something. In C, an array can be seen as a pointer to a memory space.
int an_integer[2]; // you declare an array of 2 integers
int *ptr_integer; // you declare a pointer to an integer
ptr_integer = (int *)an_integer; // here you set the value of the pointer to the address of the array, you have to cast it into an (int *) to avoid compilation warnings.
For a start, I would suggest changing:
char string;
to:
char *string;
It's pretty clear that you want the string variable to be a string rather than a single character.
In addition, you probably want to change the two lines:
sptr = &string;
printf("%s \n", &sptr);
to:
sptr = string;
printf("%s \n", sptr);
but you could equally well just pass string itself to printf.
As for the sendptr(ptr, sptr);, we can't help that much without knowing more details about it.
To fix your second function (from your edit), change:
char fnamn[] = &fname;
to:
char *fnamn = fname;
or just use fname directly. You don't have to make a copy of the pointer and the former is for things like:
char fnamn[] = "I am a string literal";
I thought it might be helpful to adding something about the difference between a char array and a pointer to a string.
In function1 below, the local variable stringPtr is a pointer to memory which contains the string "hello!". The memory containing this string will be located in a read-only section of the program. The compiler decides where to place the string "hello!" and ensures that your local variable is initialised with this memory address.
You can modify the pointer stringPtr and change it to point somewhere else. But you cannot modify the memory it points at.
Also, it is perfectly valid to use the array access notation stringPtr[2] even though it is a pointer.
In function2 the compiler will set aside 9 bytes of space on the stack for the local variable stringArray and it will ensure that this array is initialised with the string "Goodbye!". As this memory is on the stack you can modify the contents of the array.
#include <stdio.h>
void function1(void)
{
char *stringPtr = "hello!";
printf("The first char is %c\n", stringPtr[0]);
printf("The next char is %c\n", *(stringPtr+1));
// This would cause a segmentation fault, stringPtr points to read-only memory
// stringPtr[0] = 'H';
}
void function2(void)
{
char stringArray[] = "Goodbye!";
printf("The first char is %c\n", stringArray[0]);
}
int main(void)
{
function1();
function2();
return 0;
}
First of all, the return type for main should be int, not void. void main() is only well-defined if your compiler documentation explicitly lists it as a legal signature. Otherwise you invoke undefined behavior. Use int main(void) instead.
Secondly, it's time for a quick crash course on strings, arrays, and pointers.
Unlike Java, C doesn't have a dedicated string datatype; rather, strings are represented as sequences of char values terminated by a 0. They are stored as arrays of char. The string literal "hello" is stored as a 6-element array of char (const char in C++). This array has static extent, meaning it is allocated at program startup and held until the program terminates. Attempting to modify the contents of a string literal invokes undefined behavior; it's best to act as though they're unwritable.
When an array expression appears in most contexts, the type of the expression is converted from "N-element array of T" to "pointer to T", and the value of the expression is the address of the first element of the array. That's one of the reasons the string = "hello"; statement doesn't work; in that context, the type of the expression "hello" is converted from "6-element array of char" to "pointer to char", which is incompatible with the target type (which, being char, isn't the correct type anyway). The only exceptions to this rule are when the array expression is an operand of either the sizeof or unary & operators, or if it is a string literal being used to initialize another array in a declaration.
For example, the declaration
char foo[] = "hello";
allocates foo as a 6-element array of char and copies the contents of the string literal to it, whereas
char *bar = "hello";
allocates bar as a pointer to char and copies the address of the string literal to it.
If you want to copy the contents of one array to another, you need to use a library function like strcpy or memcpy. For strings, you'd use strcpy like so:
char string[MAX_LENGTH];
strcpy(string, "hello");
You'll need to make sure that the target is large enough to store the contents of the source string, along with the terminating 0. Otherwise you'll get a buffer overflow. Arrays in C don't know how big they are, and running past the end of an array will not raise an exception like it does in Java.
If you want to guard against the possibility of a buffer overflow, you'd use strncpy, which takes a count as an additional parameter, so that no more than N characters are copied:
strncpy(string, "hello", MAX_LEN - 1);
The problem is that strncpy won't append the 0 terminator to the target if the source is longer than the destination; you'll have to do that yourself.
If you want to print the contents of a string, you'd use the %s conversion specifier and pass an expression that evaluates to the address of the first element of the string, like so:
char string[10] = "hello";
char *p = string;
printf("%s\n", "hello"); // "hello" is an array expression that decays to a pointer
printf("%s\n", string); // string is an array expression that decays to a pointer
printf("%s\n", p); // p is a pointer to the beginning of the string
Again, both "hello" and string have their types converted from "N-element array of char" to "pointer to char"; all printf sees is a pointer value.
Here's a handy table showing the types of various expressions involving arrays:
Declaration: T a[M];
Expression Type Decays to
---------- ---- ---------
a T [M] T *
&a T (*)[M]
*a T
a[i] T
&a[i] T *
Declaration: T a[M][N];
Expression Type Decays to
---------- ---- ---------
a T [M][N] T (*)[N]
&a T (*)[M][N]
*a T [N] T *
a[i] T [N] T *
&a[i] T (*)[N]
*a[i] T
a[i][j] T
&a[i][j] T *
Remember that the unary & operator will yield the address of its operand (provided the operand is an lvalue). That's why your char fnamn[] = &fname; declaration threw up the "invalid initializer" error; you're trying to initialize the contents of an array of char with a pointer value.
The unary * operator will yield the value of whatever its operand points to. If the operand isn't pointing anywhere meaningful (it's either NULL or doesn't correspond to a valid address), the behavior is undefined. If you're lucky, you'll get a segfault outright. If you're not lucky, you'll get weird runtime behavior.
Note that the expressions a and &a yield the same value (the address of the first element in the array), but their types are different. The first yields a simple pointer to T, where the second yields a pointer to an array of T. This matters when you're doing pointer arithmetic. For example, assume the following code:
int a[5] = {0,1,2,3,4};
int *p = a;
int (*pa)[5] = &a;
printf("p = %p, pa = %p\n", (void *) p, (void *) pa);
p++;
pa++;
printf("p = %p, pa = %p\n", (void *) p, (void *) pa);
For the first printf, the two pointer values are identical. Then we advance both pointers. p will be advanced by sizeof int bytes (i.e., it will point to the second element of the array). pa, OTOH, will be advanced by sizeof int [5] bytes, so that it will point to the first byte past the end of the array.
#include <stdio.h>
void main()
{
int k = 10;
char string;
char *sptr;
sptr = "hello!";
int *ptr;
ptr = &k;
printf("%s \n", sptr);
printf("Sending pointer.\n");
sendptr(ptr, sptr);
}