Im new to C programming and I'd like to know how does a pointer constant differ from a constant variable in this case:
#include <stdio.h>
int main(void)
{
int cnt = 0;
char val;
char mystr[20] = “hello there!”;
char *p_str2, str2[20] = “zzzzzzzzzzzzzzzz”;
char* p_mystr = mystr;
p_str2 = str2;
while (*p_mystr != 0x00)
{
val=*p_mystr++;
cnt++;
}
return 0;
}
also, how does mystr differ from mystr[2] (what data type is each variable) and is there anything wrong with p_mystr = mystr[2]; could this be written better (ie: why is *p_mystr= mystr[2]; correct)?
Except when it is the operand of the sizeof or unary & operators, an expression of type "N-element array of T" will be converted 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. The result is not an lvalue, meaning it cannot be the target of an assignment.
So, given the declaration
char mystr[20] = "hello there!";
the following are all true:
Expression Type Decays to Result
---------- ---- --------- ------
mystr char [20] char * address of mystr[0]
&mystr char (*)[20] n/a address of mystr
*mystr char n/a value of mystr[0], or 'h'
mystr[i] char n/a i'th character
&mystr[i] char * n/a address of mystr[i]
sizeof mystr size_t n/a 20 (number of bytes in array)
The address of the array is the same as the address of the first element of the array (no storage is set aside for a mystr variable separate from the array elements themselves), so the expressions mystr, &mystr and &mystr[0] all return the same value, but the types of the expressions are different; mystr and &mystr[0] both have type char *, but &mystr has type char (*)[20], or "pointer to 20-element array of char".
The results for str2 are the same.
Given the declaration
char *p_mystr;
we get the following
Expression Type Result
---------- ---- ------
p_mystr char * value in p_mystr
*p_mystr char value of character pointed to by p_mystr
&p_mystr char ** address of p_mystr variable
sizeof p_mystr size_t number of bytes in pointer value
The table for p_str2 is the same.
Now it's a matter of matching up types. p_mystr = mystr works because both expressions have type char *; p_mystr winds up pointing to mystr[0]. Similarly, *p_mystr = mystr[2] works1 because both expressions have type char. Same for val = *p_mystr++, although note in this case that *p_mystr++ is parsed as *(p_mystr++); the increment will be applied to the pointer value, not the character value.
Note that an expression like p_mystr = &mystr; should get you a diagnostic to the effect that the types don't match.
Your question title mentions const pointers and variables, although that doesn't appear in the question body. Basically, for any type T:
T *p0; // p0 is a non-const pointer to non-const T
const T *p1; // p1 is a non-const pointer to const T
T const *p2; // p2 is a non-const pointer to const T
T * const p3; // p3 is a const pointer to non-const T
const T * const p4; // p4 is a const pointer to const t
T const * const p5; // p5 is a const pointer to const t
Which breaks down as:
You can write to p0 (change it to point to something else) and *p0 (change the thing being pointed to);
You can write to p1 and p2 (change them to point to something else), but you cannot write to *p1 or *p2 (cannot change the thing being pointed to);
You cannot write to p3 (cannot change it to point to something else), but you can write to *p3 (change the thing being pointed to);
You cannot write to p4 or p5 (cannot change them to point to something else), nor can you write to *p4 or *p5 (cannot change the thing being pointed to).
So, if you declared something like
const char *cptr = mystr;
you could not modify the contents of mystr through the cptr variable, even though mystr is not declared const itself.
Note that trying to go the other way, such as
const int foo = 5;
int *fptr = (int *) &foo;
*fptr = 6;
invokes undefined behavior; it may or may not work, depending on the implementation (the language definition allows implementations to put const-qualified objects in read-only memory).
1. If p_mystr is pointing somewhere valid, that is.
Both your variables mystr and str2 are character arrays stored on the stack. There's nothing "constant" here, except the string literals used to initialize your character arrays.
p_mystr is a pointer, mystr[2] is a character. Where is your *p_mystr= mystr[2]; supposed to be? It better not be before p_mystr's initialization to a valid address.
You just asked a mouthful!
A pointer is a very different type to a simple data type (a char * compared to a char). A char just has a single value e.g. 'a'. You can think of a pointer as a memory address - it means, go to the memory address 0x0123F1A and treat what you find there as a char. Pointers can be tricky to get your head around so it's worth reading up on e.g. here
mystr is an array of characters. In some ways it will behave like a pointer to the first item in the array, but it is genuinely a distinct type. mystr[2] has type char - it is the char found at index 2 in the array (i.e. the third char since array indices start at 0).
There is nothing wrong with p_mystr = mystr - it is safe to assign from a char-array to a char-pointer, and the meaning is to make the pointer point to the first item in the array.
*p_mystr=mystr[2] means something else. The * operator means "the value pointed to", so what this means is "in the memory address where p_mystr is pointing, copy the character mystr[2]"
Related
is the array name is actually like typing the address of the first element of the array ?
based on my understanding of the array name
the array name variable isn't a pointer that has it's own memory address and it's content is the address of the first element of the array
but it's a way of typing the address of first element in a plain english name
i will try now to explain it now visually
consider the following code it will be related to the image i'm about to show you
char[] text = "Hey";
char *ptr = text;
and now look at the image
the *ptr variable has it's own memory address and the content of the pointer is the memory address of H which is 0101
now the text variable doesn't have it's own memory address when we type text C interprets it to the memory address 0101
so basically text is 0101
am i right ?
Well, almost but not quite.
text is a variable of type char [4], it's an array of chars. Now, as per the spec, chapter 6.3.2.1/P3
Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ''array of type'' is converted to an expression with type ''pointer to type'' that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.
That means,
char * ptr = text;
is the same as writing
char * ptr = &text[0];
That said,
now the text variable doesn't have it's own memory address when we type text C interprets it to the memory address 0101
No, this is wrong. The variable text has an address (try doing &text, it'll be of type char (*) [4]). Now, since an array is a collection of same objects (member object type) in contiguous memory locations, the address of the array is the address of the first element of the array, so while printing the address of the array and the address of the first element of the array will turn out to be same - but remember, they certainly do differ in type.
For starters this declaration
char[] text = "Hey";
is not a valid C construction.:) It seems you mean
char text[] = "Hey";
An array type and a pointer type are two different types. Consider the following demonstrative program.
#include <stdio.h>
int main(void)
{
char text[] = "Hello World!";
char *ptr = "Hello World!";
printf( "sizeof( text ) = %zu\n", sizeof( text ) );
printf( "sizeof( ptr ) = %zu\n", sizeof( ptr ) );
return 0;
}
Its output might look like
sizeof( text ) = 13
sizeof( ptr ) = 8
Or if you will apply the address of operator & to the variable text like &text then the type of the expression will be char ( * )[13]. While applying the operator to the variable ptr like &ptr then the type of the expression will be char **.
Indeed according to the C Standard an array designator is implicitly converted in expressions (except the expressions mentioned above) to a pointer to its firs element.
So you may write
char text[] = "Hey";
char *ptr = text;
The values of the expressions &text and ptr (though they have different types) will be equal because they both point to the initial address of the extent of the memory occupied by the array.
The fact that an array designator is converted to a pointer to its first element is related to how the compiler adjusts a function parameter having an array type to the type of pointer to the array element type. That is for example these two function declarations declare the same one function
void f( char s[] );
and
void f( char *s );
Say we have the following array:
char *names[]={"Abc", "Def", "Ghi", "Klm", "Nop"};
If we want to create a pointer that points to the array above, why should we use a two-level pointer as follows?
char **p1 = names;
Thanks.
Your names is an array [], of char *, i.e., an array of pointers to char.
Meanwhile p1 is a pointer which points to a pointer to char, i.e., a pointer to char *. You can assign names to it because the array decays to a pointer to its first element, and the first element of names is a pointer to char, hence names decays to a pointer to char *. This is the same type – char ** – as p1, therefore they are compatible.
(On another note, the element type of names is incorrect; the string literals are constant, and thus it should be const char *names[], and similarly p1 should be const char** – pointer to pointer to const char.)
You can see it this way, when you need to point to an integer array, you need to use a pointer to int.
int arr[];
int* a;
a = arr;
So, in this context, you need a pointer to the elements in the array names[]. What are the elements in that array. Its char*. So you would need a pointer to char*. Which translates to pointer to pointer to char.
That is
char *names[]={"Abc", "Def", "Ghi", "Klm", "Nop"};
char **p1 = names;
You did not create a pointer to array of pointers .It actually is pointer to first pointer of array.
If you want to create a pointer to array of pointers write something like this -
char *names[MAX];
char* (*p1)[MAX] = &names;
If you want to create a pointer that points to array
char *names[]={"Abc", "Def", "Ghi", "Klm", "Nop"};
then you have to write
char * ( *p1 )[sizeof( names ) / sizeof( *names )] = &names;
If you want to create a pointer that points to the elements of the array then you indeed should write
char **p1 = names;
In this case pointer p1 is initialized by the address of the address of the first character of string literal "Abc".
So for example expression *p1 will contain the value of the first element of array names that in turn (the value) is the address of the first character of string literal "Abc" and has type char *.
If you will apply dereferencing the second time **p1 you will get the first character of the string literal itslef that is 'A'.
For example
printf( "%c\n", **p1 );
To make it more clear let's consider a general situation.
If you have an array with elements of type T like this
T a[N];
then this array in expressions is converted to pointer to its first element that will have type T *. So if you want to declare such a pointer yourself you should write
T *p1 = a;
This record is equivalent to
T *p1 = &a[0];
In your original example type T corresponds to type char * - the type of the elements ofarray names. So after substitution char * for T you will get
char * *p1 = names;
^^^^^^
T
EDIT: Thanks to the comment, the array is actually bound here: because the compiler can deduce its size from the initializers.
From its declaration, names is: an array of pointers to char. A bound array decays to a pointer to its first element. Elements of names being pointer to char, when used in an expression names is implicitly converted to a pointer to a pointer to char.
This is why you can assign names in your second line:
char **p1 = names;
So p1 points to the first element in names, which for most practical purposes is like pointing to the array (in memory, an array being juxtaposed objects). Technically, you are pointing to the first element though.
I've been looking through the site but haven't found an answer to this one yet.
It is easiest (for me at least) to explain this question with an example.
I don't understand why this is valid:
#include <stdio.h>
int main(int argc, char* argv[])
{
char *mystr = "hello";
}
But this produces a compiler warning ("initialization makes pointer from integer without a cast"):
#include <stdio.h>
int main(int argc, char* argv[])
{
int *myint = 5;
}
My understanding of the first program is that creates a variable called mystr of type pointer-to-char, the value of which is the address of the first char ('h') of the string literal "hello". In other words with this initialization you not only get the pointer, but also define the object ("hello" in this case) which the pointer points to.
Why, then, does int *myint = 5; seemingly not achieve something analogous to this, i.e. create a variable called myint of type pointer-to-int, the value of which is the address of the value '5'? Why doesn't this initialization both give me the pointer and also define the object which the pointer points to?
In fact, you can do so using a compound literal, a feature added to the language by the 1999 ISO C standard.
A string literal is of type char[N], where N is the length of the string plus 1. Like any array expression, it's implicitly converted, in most but not all contexts, to a pointer to the array's first element. So this:
char *mystr = "hello";
assigns to the pointer mystr the address of the initial element of an array whose contents are "hello" (followed by a terminating '\0' null character).
Incidentally, it's safer to write:
const char *mystr = "hello";
There are no such implicit conversions for integers -- but you can do this:
int *ptr = &(int){42};
(int){42} is a compound literal, which creates an anonymous int object initialized to 42; & takes the address of that object.
But be careful: The array created by a string literal always has static storage duration, but the object created by a compound literal can have either static or automatic storage duration, depending on where it appears. That means that if the value of ptr is returned from a function, the object with the value 42 will cease to exist while the pointer still points to it.
As for:
int *myint = 5;
that attempts to assign the value 5 to an object of type int*. (Strictly speaking it's an initialization rather than an assignment, but the effect is the same). Since there's no implicit conversion from int to int* (other than the special case of 0 being treated as a null pointer constant), this is invalid.
When you do char* mystr = "foo";, the compiler will create the string "foo" in a special read-only portion of your executable, and effectively rewrite the statement as char* mystr = address_of_that_string;
The same is not implemented for any other type, including integers. int* myint = 5; will set myint to point to address 5.
i'll split my answer to two parts:
1st, why char* str = "hello"; is valid:
char* str declare a space for a pointer (number that represents a memory address on the current architecture)
when you write "hello" you actually fill the stack with 6 bytes of data
(don't forget the null termination) lets say at address 0x1000 - 0x1005.
str="hello" assigns the start address of that 5 bytes (0x1000) to the *str
so what we have is :
1. str, which takes 4 bytes in memory, holds the number 0x1000 (points to the first char only!)
2. 6 bytes 'h' 'e' 'l' 'l' 'o' '\0'
2st, why int* ptr = 0x105A4DD9; isn't valid:
well, this is not entirely true!
as said before, a Pointer is a number that represent an address,
so why cant i assign that number ?
it is not common because mostly you extract addresses of data and not enter the address manually.
but you can if you need !!!...
because it isn't something that is commonly done,
the compiler want to make sure you do so in propose, and not by mistake and forces you to CAST your data as
int* ptr = (int*)0x105A4DD9;
(used mostly for Memory mapped hardware resources)
Hope this clear things out.
Cheers
"In C, why can't an integer value be assigned to an int* the same way a string value can be assigned to a char*?"
Because it's not even a similar situation, let alone "the same way".
A string literal is an array of chars which – being an array – can be implicitly converted to a pointer to its first element. Said pointer is a char *.
But an int is not either a pointer in itself, nor an array, nor anything else implicitly convertible to a pointer. These two scenarios just don't have anything in common.
The problem is that you are trying to assign the address 5 to the pointer. Here you are not dereferencing the pointer, you are declaring it as a pointer and initializing it to the value 5 (as an address which surely is not what you intend to do). You could do the following.
#include <stdio.h>
int main(int argc, char* argv[])
{
int *myint, b;
b = 5;
myint = &b;
}
void check(void* elemAddr){
char* word = *((char**)elemAddr);
printf("word is %s\n",word);
}
int main(){
char array[10] = {'j','o','h','n'};
char * bla = array;
check(&bla);
check(&array);
}
Output:
word is john
RUN FINISHED; Segmentation fault; core dumped;
First one works, but second not. I don't understand why this happens.
The problem is, when we do &array, we are getting a char (*)[10] from an char [10], instead of a char **.
Before we do our experiment, I will emphasize that, when we pass an array as an argument to a function, C actually casts the array to a pointer. The big bucket of data is not copied.
Thus, int main(int argc, char **argv) is identical to int main(int argc, char *argv[]) in C.
This made it available for us to print the address of an array with a simple printf.
Let's do the experiment:
char array[] = "john";
printf("array: %p\n", array);
printf("&array: %p\n", &array);
// Output:
array: 0x7fff924eaae0
&array: 0x7fff924eaae0
After knowing this, let's dig into your code:
char array[10] = "john";
char *bla = array;
check(&bla);
check(&array);
bla is char *, and &bla is char **.
However, array is char [10], and &array is char (*)[10] instead of char **.
So when you pass &array as an argument, char (*)[10] acts like a char * when passing as an argument, as is said above.
Therefore **(char **) &bla == 'j' while *(char *) &array == 'j'. Do some simple experiments and you will prove it.
And you are casting void *elemAddr to a char ** and try to deference it. This will only work with &bla since it is char **. &array will cause a segfault because "john" is interpreted as an address as you do the cast.
For check(&bla); you are sending pointer to pointer
void check(void* elemAddr){
char* word = *((char**)elemAddr); // works fine for pointer to pointer
printf("word is %s\n",word);
}
This is working fine.
But, for check(&array); you are passing pointer only
void check(void* elemAddr){
char* word = *((char**)elemAddr); // This is not working for pointer
char* word = *(char (*)[10])(elemAddr); // Try this for [check(&array);]
printf("word is %s\n",word);
}
Full Code--
Code for check(array);:
void check(void* elemAddr){
char* word = *(char (*)[10])(elemAddr);
printf("word is %s\n",word);
}
int main() {
char array[10] = {'j','o','h','n'};
check((char*)array);
return 0;
}
Code for check(&bla);:
void check(void* elemAddr){
char* word = *((char**)elemAddr);
printf("word is %s\n",word);
}
int main() {
char array[10] = {'j','o','h','n'};
char* bla = array;
check(&bla);
return 0;
}
The C specification says that array and &array are the same pointer address.
Using the name of an array when passing an array to a function will automatically convert the argument to a pointer per the C specification (emphasis mine).
6.3.2.1-4
Except when it is the operand of the sizeof operator or the unary &
operator, or is a string literal used to initialize an array, an
expression that has type ‘‘array of type’’ is converted to an
expression with type ‘‘pointer to type’’ that points to the initial
element of the array object and is not an lvalue. If the array object
has register storage class, the behavior is undefined.
So calling func(array) will cause a pointer to char[] to be passed to the function. But there is a special case for using the address-of operator on an array. Since array has type "array of type" it falls into the 'Otherwise' category of the specification (emphasis mine).
6.5.3.2-3
The unary & operator yields the address of its operand. If the operand
has type ‘‘type’’, the result has type ‘‘pointer to type’’. If the
operand is the result of a unary * operator, neither that operator nor
the & operator is evaluated and the result is as if both were omitted,
except that the constraints on the operators still apply and the
result is not an lvalue. Similarly, if the operand is the result of a
[] operator, neither the & operator nor the unary * that is implied by
the [] is evaluated and the result is as if the & operator were
removed and the [] operator were changed to a + operator. Otherwise,
the result is a pointer to the object or function designated by its
operand
So calling func(&array) will still cause a single pointer to be passed to the function just like calling func(array) does since both array and &array are the same pointer value.
Common-sense would lead you to believe that &array is a double pointer to the first element of the array because using the & operator typically behaves that way. But arrays are different. So when you de-reference the passed array pointer as a double pointer to the array you get a Segmentation fault.
This is not a direct answer to your question, but it might be helpful to you in the future.
Arrays are not pointers:
type arr[10]:
An amount of sizeof(type)*10 bytes is used
The values of arr and &arr are necessarily identical
arr points to a valid memory address, but cannot be set to point to another memory address
type* ptr = arr:
An additional amount of sizeof(type*) bytes is used
The values of ptr and &ptr are typically different, unless you set ptr = (type*)&ptr
ptr can be set to point to both valid and invalid memory addresses, as many times as you will
As with regards to your question: &bla != bla == array == &array, and therefore &bla != &array.
One problem is that your char array is NOT NECESSARILY going to be null-terminated. Since array is an automatic variable that is allocated locally on the stack, it is not guaranteed to be zeroed-out memory. So, even though you are initializing the first 4 chars, the latter 6 are left undefined.
However ...
The simple answer to your question is that &bla != &array so your check() function is assuming it will find null-terminated character arrays at 2 different addresses.
The following equations are true:
array == &array // while not the same types exactly, these are equivalent pointers
array == bla
&array == bla
*bla == array[0]
&bla is never going to equal anything you want because that syntax references the address of the bla variable on the local stack and has nothing to do with its value (or what it points to).
Hope that helps.
OK, I'm having trouble understanding pointers to pointers vs pointers to arrays.
Consider the following code:
char s[] = "Hello, World";
char (*p1)[] = &s;
char **p2 = &s;
printf("%c\n", **p1); /* Works */
printf("%c\n", **p2); /* Segmentation fault */
Why does the first printf work, while the second one doesn't?
From what I understand, 's' is a pointer to the first element of the array (that is, 'H').
So declaring p2 as char** means that it is a pointer to a pointer to a char. Making it point to 's' should be legal, since 's' is a pointer to a char. And thus dereferencing it (i.e. **p2) should give 'H'. But it doesn't!
Your misunderstand lies in what s is. It is not a pointer: it is an array.
Now in most contexts, s evaluates to a pointer to the first element of the array: equivalent to &s[0], a pointer to that 'H'. The important thing here though is that that pointer value you get when evaluating s is a temporary, ephemeral value - just like &s[0].
Because that pointer isn't a permanent object (it's not actually what's stored in s), you can't make a pointer-to-pointer point at it. To use a pointer-to-pointer, you must have a real pointer object to point to - for example, the following is OK:
char *p = s;
char **p2 = &p;
If you evaluate *p2, you're telling the compiler to load the thing that p2 points to and treat it as a pointer-to-char. That's fine when p2 does actually point at a pointer-to-char; but when you do char **p2 = &s;, the thing that p2 points to isn't a pointer at all - it's an array (in this case, it's a block of 13 chars).
From what I understand, 's' is a pointer to the first element of the array
No, s is an array. It can be reduced to a pointer to an array, but until such time, it is an array. A pointer to an array becomes a pointer to the first element of the array. (yeah, it's kinda confusing.)
char (*p1)[] = &s;
This is allowed, it's a pointer to an array, assigned the address of an array. It points to the first element of s.
char **p2 = &s;
That makes a pointer to a pointer and assigns it the address of the array. You assign it a pointer to the first element of s (a char), when it thinks it's a pointer to a pointer to one or more chars. Dereferencing this is undefined behavior. (segfault in your case)
The proof that they are different lies in sizeof(char[1000]) (returns size of 1000 chars, not the size of a pointer), and functions like this:
template<int length>
void function(char (&arr)[length]) {}
which will compile when given an array, but not a pointer.
Here's the sample that works, plus printouts of pointer addresses to make things simple to see:
#include <stdio.h>
char s[] = "Hello, World";
char (*p1)[] = &s;
char *p2 = (char*)&s;
int main(void)
{
printf("%x %x %x\n", s, p2, *p2);
printf("%x\n", &s); // Note that `s` and `&s` give the same value
printf("%x\n", &s[0]);
printf("%c\n", **p1);
printf("%c\n", *p2);
}