I tried to figure out the behavior of two pointers pointing the same address. And to try it myself I wrote the code below. This one confused me. What is the difference here ?
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *ptr = "hey!";
char *copyPtr = ptr;
printf("%p\n", ptr);
printf("%p\n", copyPtr);
printf("%s\n", ptr);
printf("%s\n", copyPtr);
copyPtr = "changed!";
printf("%p\n", ptr);
printf("%p\n", copyPtr);
printf("%s\n", ptr);
printf("%s\n", copyPtr);
printf("\n\n");
int *ptr1 = malloc(sizeof(int));
*ptr1 = 1;
int *copyPtr1 = ptr1;
printf("%p\n", ptr1);
printf("%p\n", copyPtr1);
printf("%d\n", *ptr1);
printf("%d\n", *copyPtr1);
*copyPtr1 = 2;
printf("%p\n", ptr1);
printf("%p\n", copyPtr1);
printf("%d\n", *ptr1);
printf("%d\n", *copyPtr1);
free(ptr1);
}
Here is the output. I was waiting the output to be like "changed!" and "changed!". ptr and copyPtr should be pointing to the same address right ? When I change the value inside this address they should both change and the address should remain same. Why is that not the case ?
On the other hand when it is done with dynamic memory allocation there seems like no problem.
0x4007e4
0x4007e4
hey!
hey!
0x4007e4
0x4007ed
hey!
changed!
0xa9f420
0xa9f420
1
1
0xa9f420
0xa9f420
2
2
The answers to similar questions didn't really satisfy me, or this may be a duplicate question, I am therefore sorry in that case..
In the first case, you change the value of copyPtr to the address of a string constant. This string constant lives at a different address from the first one. So after this change, the pointer values are different, as are what they point to.
In the second case you're not actually changing copyPtr1. You're dereferencing it and changing the value it points to, which is the same value that ptr1 points to. So the change in value is reflected when you dereference ptr1. The fact that you used malloc in this case is irrelevant. What is relevant is that you dereferenced the pointer in this case, while in the former you did not.
In order for the first case to show a change in ptr, you would need to dereference copyPtr instead of changing its value. Note however that string constants are just that -- constant. You can't change them, and attempting to do so will likely cause a segmentation fault. If on the other hand the memory pointed to is created dynamically, then you can change it.
For example, this is invalid:
char *ptr = "hey!";
char *copyPtr = ptr;
strcpy(copyPtr, "hi!"); // invalid: attempt to write to a string constant
But this will work:
char *ptr = strdup("hey!");
char *copyPtr = ptr;
strcpy(copyPtr, "hi!"); // OK, but be careful not to overrun the buffer
There is a difference between the first change - copyPtr = "changed!"; and the second change - *copyPtr1 = 2;
While the 1st one changes address of copyPtr to point to a const section (.ro section) in the object file while the 2nd one keeps the pointer copyPtr1 pointed to the same memory in heap just modifies it's contents.. Hope that helps!
The code:
copyPtr = "changed!";
changes the pointer to point to the new string literal as shown in the output:
0x4007e4
0x4007ed
hey!
changed!
If you want to change the value at the original address, use strcpy().
In the second one where you malloc memory, you are dereferencing the pointer so the value changed as expected (rather than the pointer).
in this statement
copyPtr = "changed!";
there is changed the value stored in the pointer copyPtr itself.
Now the pointer points to the first character of the string literal "changed!".
In this statement
*ptr1 = 1;
there is changed the object pointed to by the pointer ptr1 because in the statement the pointer is dereferenced. The value of the pointer itself was not changed. It still keeps the address of the allocated memory in the statement
int *ptr1 = malloc(sizeof(int));
You could achieve the same result with the previous pointers. For example
char s[] = "hey!";
char *ptr = s;
char *copyPtr = ptr;
// ...
*copyPtr = 'H';
puts( ptr );
puts( copyPtr );
Thus in the code snippets above there are changed different values. In the first example there is changed the value of the pointer itself.
And in the second example there is changed the value of the object pointed to by the pointer. The value of the pointer itself was not changed. As result the both pointers still point to the same one object that was changed.
Related
char *s, *p = s;
size_t len = 0;
while (str[len++]);
s = malloc(sizeof(*s) * (len + 1));
How come here: char *s, *p = s; gives warning, but s is going to be initialized with malloc later.
chl/string.c:9:15: warning: āsā may be used uninitialized in this function [-Wmaybe-uninitialized]
9 | char *s, *p = s;
^
Since p is a pointer, pointing to s, won't p be updated as well when it points to s when s will be memory allocated?
Why would I have to do this instead:
char *s, *p;
size_t len = 0;
while (str[len++]);
s = malloc(sizeof(*s) * (len + 1));
p = s;
I thought pointers can change to what it points to, so why isn't p being updated as a pointer? Or if I'm seeing this wrong, why can't I just do *p = s, because s soon is going to be initialized, and p will point to s, so won't p update too?
Let's break this down a little.
What you have essentially is this:
char *s;
char *p = s;
s = malloc(...);
You're proposing that when s gets initialized (by malloc's return value), the value of p should also update.
But, as you've discovered this is not the case. Initially, when you do char *s, s can point to anything. It is not yet initialized.
Subsequently, when you do char *p = s;, you are assigning the current value of s to p -- which could be anything.
If you change the value of s, that doesn't automatically change the value of p. They are distinct variables. They are both pointers - but that doesn't mean they should point to the same thing just because one was initialized from the other.
There is no intrinsic link between these two pointers, even if you assign one to the other. The point is, even if they do point to the same thing at one point in time, you can change what one points to in the future without affecting the other.
Its actually no different from assigning to a non-pointer variable and asserting that it should be updated automatically, e.g.
int i;
int j;
i = j;
j = 5;
printf("%d\n", i); // Prints rubbish
printf("%d\n", j); // Prints 5
Here, j is initialized and the printf is as expected. Meanwhile, i was initialized from j's rubbish value -- the value that happened to be lying in memory at j's location (and that could be anything). Yet, I doubt anyone would suggest that i should "automatically" update in this case.
UPDATE:
The following update is in response to this followup comment made:
Here's why I thought it would update.. char *s = malloc(100); char *p
= s; see this, right? p[0] = 'e' for example will also change s[0], so I thought that since if assigning the element of p by index would also
change the element of s by index, there would be change/update, right?
How come p[0] = 'e' changes the element of both s and p, even though p
just assigned the current value of malloc? They are different pointers
but point to the same memory block, that's why! Am I right?
In this example, p and s again point to the same memory. When you do the assignment p[0] = 'e', you are NOT changing p or s -- you are in fact changing the value pointed to by p. And, since p and s point to the same memory, the change you've made will be visible through both p and s -- when you dereference either. Below is an in-depth example - I recommend compiling it and running it to see what gets printed, and read the comments which explain what is happening at each step.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
// this initializes s to point to some block of memory, e.g. address 0x560890f49260 when I run it locally
// it can store 100 bytes (chars) of data
char *s = malloc(100);
// this initializes p to point to the same block of memory as s => 0x560890f49260
char *p = s;
// this prints out the value of p and s
// they are of type 'pointer', so use %p
// this shows their address as being the same
printf("This is where p points to: %p\n", p);
printf("This is where s points to: %p\n", s);
// this sets the 1st byte at the location pointed to by p
// the thing we're changing is at address 0x560890f49260
// this "array" notation is just syntactic sugar for dereferencing a pointer - see below
p[0] = 'e';
// but p and s are unchanged
printf("This is where p points to: %p\n", p);
printf("This is where s points to: %p\n", s);
// this also changes the 1st byte (same as *p = 'e' and p[0] = 'e')
// here we're using the dereferencing syntax explictly
*(p + 0) = 'e';
// and p and s are still the same
printf("This is where p points to: %p\n", p);
printf("This is where s points to: %p\n", s);
// this changes the 2nd byte (same as p[1] = 'f')
// the thing we're changing is at address 0x560890f49261 - i.e. the next byte
*(p + 1) = 'f';
// and p and s still haven't changed
printf("This is where p points to: %p\n", p);
printf("This is where s points to: %p\n", s);
// this prints the 1st and 2nd byte pointed to by p and s
// they show the same thing in both cases - since p and s point to the same thing
printf("First byte pointed to by p: %c\n", p[0]);
printf("First byte pointed to by s: %c\n", s[0]);
printf("Second byte pointed to by p: %c\n", p[1]);
printf("Second byte pointed to by s: %c\n", s[1]);
// now p is pointing to something new, e.g. address 0x5617ba3ef6e0 when I run it locally
p = malloc(100);
// we see that p **HAS** changed, but s has **NOT** changed
// they are now pointing to different things
printf("This is where p points to: %p (new location!)\n", p);
printf("This is where s points to: %p (old location!)\n", s);
// this sets the 1st byte pointed to by p to be 'g'
p[0] = 'g';
// we can see that the 1st byte pointed to by p is 'g'
printf("First byte pointed to by p: %c\n", p[0]);
// while the first byte pointed to be s is unaffected
// since p and s point to different things
printf("First byte pointed to by s: %c\n", s[0]);
// always free your memory
free(p);
free(s);
return 0;
}
Oh no, p is not pointing to s.
Your statement:
char *p = s;
It's saying "copy the value of pointer s, into pointer p", so whatever may be the address stored in s (which is not initialized) it's what's going to be the value stored in p.
Once s is assigned the value of the malloc, p will remain with the initial value and s will be different.
I just started learning C and I'm quite unsure of how to "correctly" access and edit values of a character pointer.
For example:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char* text = malloc(20);
char* othertext = "Teststring";
do
{
*text++ = *othertext++;
} while (*othertext != '\0');
printf("%s\n", text + 3);
free(text);
return 0;
}
Firstly, why does the do-while function not work? The content of "othertext" doesn't get copied to the "text" pointer. Furthermore, the program crashes when free(text) is being executed!
We know that this code works if we add a second pointer:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char* text = malloc(20);
char* othertext = "Teststring";
char *ptr1 = text;
char *ptr2 = othertext;
do
{
*ptr1++ = *ptr2++;
} while (*ptr2 != '\0');
printf("%s\n", text + 3);
free(text);
return 0;
}
But both pointers have basically the same address! They have the same values in the debugger, so how does a second pointer make any difference?
As a final note: We are not allowed to use string.h. And we do know there's a subtle difference between arrays and pointers. But we need to specifically understand how char* works!
You should pass to free() the pointer returned by malloc() (the same address). You are passing the incremented pointer i.e. the text pointer now doesn't have the address of the pointer returned by malloc() instead it's an the address of the last element of text, use another pointer to copy the data, or better an index
size_t i;
for (i = 0 ; othertext[i] != '\0' ; ++i)
text[i] = othertext[i];
text[i] = '\0';
You say
But both pointers have basically the same address!
This is not true, try this
printf("%p -- %p\n", (void *) text, (void *) ptr1);
You modify the value of the text pointer in your loop, such that at the end it's not pointing to the beginning of the memory region you allocated; that's (part of) why you don't see the text, and why the free crashes.
You need to preserve that original pointer value (which you do in your second snippet).
You are actually changing the address that text is pointing too.
Consider a very simple memory in which text points to address 5 and othertext points to address 42 on which the T of TestString has been placed.
You now copy the character found at address 42 to address 5, so that address 5 also contains a T. However, you now increment the address that text is pointing too. In other words, text now points at address 6. You also increment othertext which now points to address 43.
In the next round you copy the e found at address 43 to address 6 and increment both again. This is all fine.
However after you are done copying text will point to 5 + 10 = 15. On address 15 however you can not print anything, nor can you remove what is there.
In your second piece of code there are no problems because text keeps pointing to address 5.
do this printf inside the loop after the assignment line. I think you will see why it's not working ;)
printf("%s\n", text);
I'm little bit confused about usage pointer arithmetic. I ask confusing question in the code as comments. I think when it is increased, the other also must be increased. Can someone explain?
#include <stdio.h>
int main()
{
const char *str = "abcde";
const char *temp = str; // str is pointer to address of first element of temp isn't it?
printf("%d\n", temp - str); // zero okey
printf("temp str\n");
printf("%d %d\n", temp, str); // shows same adresses
str++; // hard to understand a point is here
printf("%d %d\n", temp, str); // why weren't also temp increased?
temp++;
printf("%d %d\n", temp, str); // why weren't also str increased?
temp++;
printf("%d %d\n", temp, str); // why weren't also str increased?
return 0;
}
temp and str both are different pointer variables. Modifying any of them will not cause the modification of other but modifying the data they point to will have effect.
You should keep in mind that in your case you can modify str and temp but can't modify the string literal they points to because string literals are not modifiable.
Also note that for pointer data type %p is used as format specifier in printf to print the address they point to.
temp won't be increased by increasing str just as b won't be increased by increasing a in int a=0, b=0;. They are independent variables.
str is pointer to address of first element of "abcde" and it won't have any relationships with temp because it is defined before temp is defined.
By the way, do not try to print pointers with %d. This is undefined behavior because the types don't match.
#include <stdio.h>
int main(void)
{
const char *str = "abcde";
const char *temp = str; // str is pointer to address of first element of temp isn't it?
printf("%ld\n", (long)(temp - str)); // zero okey
printf("temp str\n");
printf("%p %p\n", (void*)temp, (void*)str); // shows same adresses
str++; // hard to understand a point is here
printf("%p %p\n", (void*)temp, (void*)str); // why weren't also temp increased?
temp++;
printf("%p %p\n", (void*)temp, (void*)str); // why weren't also str increased?
temp++;
printf("%p %p\n", (void*)temp, (void*)str); // why weren't also str increased?
return 0;
}
In your code, temp and str are themselves two different variable, however, the data they point to, are same.
If you modify the content pointed by either of them, you can see the change reflected through other.
Also, FWIW, for printing address, change
printf("%d %d\n", temp, str);
to
printf("%p %p\n", (void *) temp, (void *)str);
otherwise, by violating the requirement of appropriate type of parameters to the format specifier, you'll invoke undefined behavior.
const char *temp = str;
means temp pointer takes value of str pointer.
They are not linked.
you can change str without changing temp because it's like
*temp = &(str[0]);
*temp value is the address of 'a' from string "abcde"
if you str++
*temp value is the address of 'a' from string "abcde" and *str is the 'b'
i don't know what more i wan do for you.
This declaration
const char *str = "abcde";
means the following. There is allocated memory for variable str and it is initialized by the address of the first character of string literal "abcde"
In this declaration
const char *temp = str;
there is allocated memory for another pointer with name temp and the pointer gets a copy of the value stored in variable str.
So now you have two cells of memory each of them contains the address of the first character of the string literal.
This statement
str++; // hard to understand a point is here
means that the value stored in str was increased. The previous value was the address of the first character of the string literal. After increasing the value now it is equal to the address of the second character of the string literal.
You can check this by executing statements with a call to function printf before this statement and after it
printf( "%s\n", str );
str++; // hard to understand a point is here
printf( "%s\n", str );
The value stored in variable temp was not changed.
After this statement
temp++;
the both variables have equal values that are pointers to the second character of the string literal. The values stored in different cells of memory named str and temp.
After the second statement
temp++;
variable temp will have the value that equal to the address of the third character of the string literal. The value stored in variable str was not changed.
As you should know string literals include a terminating zero. You can output all characters of a string literal until the terminating zero will be encountered.
Consider the following code snippet
const char *str = "abcde";
const char *temp = str;
while ( *temp != '\0' ) printf( "%s\n", temp++ );
After the loop variable temp will have value that points to the terminating zero of the string literal. At the same time value stored in str will not be changed and will point to the first character of the string literal as before.
In the next code:
char i,*p;
i = 65;
p = &i;
p = (char *) 66;
(*p)++;
printf("%d",p);
I got segmentation fault. I didn't understand why. I have a pointer to a char (in this case char 66=C), and then I change it value, which is also 66 - to 67. Are the values of char "protected" from this change? Is it happen also with others, except char?
I tried to understand the idea that stand behind this thing (and not only fix it). Thanks.
Here is the problem:
p = (char *) 66;
It should be:
*p = 66;
p is a pointer to a char, so you cannot assign values like 66 to it. You can derefernce p in order to assign values to where the pointer "looks".
If you want to print the value where p points to, you must use again the dereference operator (*) like this:
printf("%d", *p); // prints the value where p points to
If you want to print the pointer address you can do this:
printf("%p", p); // prints the address where p points
A character pointer doesn't store a character, it stores an address where a character can be found. So
p = (char *)66;
says that p points to address number 66, where a character can be found. Odds are that address isn't even accessible by your program, much less that it stores a character.
I am speaking in Standard, K&R C.
Given:
const char a[] = {1, 2, 3};
const char *p = NULL;
Are these two statements equivalent:
*p = a;
p = a;
Each of them would be on the third line of the snippet.
1 and 2 certainly don't look the same.
What's the difference between the two then?
No.
p = a initializes the pointer to point to something else (usually it copies another pointer or you will point to a reference, ala p = &a.
*p = a initializes what p refers to. You are "dereferencing" (looking at) what p points to. If p points to NULL as in your example, you will crash (this is good! you do not want to accidentally access something and mess your program up).
In this case, p = a will point to the first of the array a[], and *p = a will attempt to change the first of the array (it won't work; you have it declared const).
Here is a small example program in C++, with almost identical syntax to C.
#include <iostream>
int main()
{
char arr[5] { 'a', 'b', 'c' }; // arr[3] and arr[4] are set to 0
char *ptr = arr; //point to 'a'
for (int i = 0; i != 5; i++)
{
*ptr = 'f'; //this changes the array
ptr++; //this changes what the pointer points to; moves it to next in array
}
for (int i = 0; i != 5; i++)
{
std::cout << *ptr << " ";
}
//outputs f f f f f
}
The * operator is what we call the dereference operator. To understand what it does, you must understand exactly what a pointer is.
When you do
char *p;
the "variable" p does not use the same amount of memory as a normal char, it uses more memory: it uses the amount of memory needed to correctly identify a memory position in your computer. So, let's say you use a 32-bit architecture, the variable p occupies 4 bytes (not the 1 byte you would expect from a char).
So, when you do
p = a;
you see clearly that you are changing the contents of the variable p, that is, you are putting another 32-bit number inside it: you are changing the address it is pointing to.
After that line executes, the value of p is the memory address of the character array a.
Now for the dereference operator. When you do
*p = 'Z';
you are telling the compiler that you want to store the value 'Z' ON THE ADDRESS pointed by p. So, the value of p remains the same after this line: it continues to point to the same address. It's the value of this address that has changed, and now contains 'Z'.
So, the final effect of
char a[] = {'a', 'b', 'c'};
char p = a;
*p = 'Z';
is the same as changing the first position of the array a to 'Z', that is:
char a[] = {'a', 'b', 'c'};
a[0] = 'Z';
NOTE: there is a difference when making a pointer point to an array: the variable that contains the array contains only the address of the first element, so a is the same as "the starting address of the array".
Usually you will see the & operator. It is an operator used to obtain the memory address of a variable. For example:
int number = 42;
int pointer = &number;
printf("%d", *pointer);
Here we have them all. The first line creates an integer variable and stores 42 inside it.
The second line creates a pointer to an integer, and stores the address of the variable number inside it.
The third line reades the value on the address pointed by the pointer.
So, the trick is to read *x as on the address pointed by x and &x as the address of x.
The first dereferences a null pointer, and tries to assign it the address of the array. This will be a compiler error, because char != char []. If it weren't, it would likely crash.
The second sets p to point to the the array.
I think you are mistaking:
char a[8];
char *p=a;
which is legal and does the same as:
char a[8];
char *p=NULL;
p=a;
with:
char a[8];
char *p=NULL;
*p=a;
which as others said would generate a compile error or a segmentation fault.
In the left side of declarations you should read *x as pointer(x) while in
statements it must be read as value_pointed_by(x). &x on the other hand
would be pointer_to(x)
Here's a trick I used when I learned C (and still use today).
Whenever you see the * in front of a variable in your code, automatically read it as "what is pointed to by".
So you should be able to easily see that setting "p" to "a" is very different from setting "what is pointed to by p" to "a".
Also, since p is supposed to be pointing at a char, setting that char p is pointing at (currently the "char" at memory location 0 assuming null is 0) to a char pointer (a) is probably going to fail at compile time if you are lucky (depending on your compiler and lint settings it may actually succeed.)
from comment:In a function declaration like f(char c), I usually try to separate out the variable name from the rest of it--so it would be f( (char) c). so c is a char*. Exactly like a variable definition.
Also & usually reads as "The address of", but that gets even more iffy. A few examples of how I read things to myself. May or may not help you.
int a[] = {1,2,3}; // I mentally parse this as (int[]) a, so a is an int array.
int *p; // p is a pointer to "integers"
int i;
p=a; // p acts exactly as a does now.
i=*p; // i is "What is pointed to by" p (1)
i=p; // i is some memory address
i=*a; // i is what is pointed to by a (1)
i=p[1]; // Don't forget that * and [] syntax are generally interchangable.
i=a+1; // Same as above (2).
p=&i; // p is the address of i (it can because it's a pointer)
// remember from hs algebra that = generally reads as "is", still works!
*p=7; // what is pointed to by p (i) is 7;
a=*i; // whoops, can't assign an array. This is the only difference between
// arrays and pointers that you will have to deal with often, so feel
// free to use which ever one you are more comfortable with.
char c='a';
char * d = &c;// d is a char pointer, and it is the address of c
char ** e ; // e is a pointer to a memory location containing
// a pointer to a char!
e=&d; // gets d's address. a pointer to a pointer gets
// the address of a pointer. Messy but gets the job done
**e=5; // what is pointed to by what is pointed to by e is 5.
*e=&'f'; // what is pointed to by e (which is a char * itself, and is still d!)
// is set to the address of the memory location holding the value 'f'.
// does not change c or e, just d!
I haven't touched c in 10 years, so some of this may be a bit wrong, but it helps me to read it out loud that way.
No, they are not equivalent
If p = NULL, then doing *p = a will give you a segmentation fault.
Because "*p" dereferences the pointer wouldnt this make "p" a "char**" ?
This would point "p" to the first array as expected.
I guess they are not the same.