usage pointer arithmetic confusion - c

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.

Related

Why is the compiler giving a warning that a pointer may be uninitialized when it's going to be initialized and won't the pointer update?

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.

C char pointer get a specific character

probably a dumb question but how do you access a specific character in a char pointer?
I've tried following...
char *pointer = "Hello";
printf("%s", pointer); // prints "Hello"
printf("%s", &pointer[0]); // also prints "Hello"
But what I want is printf(???) => "H". A single character. Or the "e". How is that possible?
pointer is a pointer to char, also called a char *.
After char *pointer = "Hello";, pointer points to the “H”.
When printf is given %s, it takes a char * and prints all the characters it finds starting at that location, until a null character is seen.
To tell printf to print a single character, pass it the actual character value (not a pointer) and use %c:
printf("%c", *pointer);
or:
printf("%c", pointer[0]);
or, for the “e” instead of the “H”:
printf("%c", pointer[1]);
char* pointer = "Hello";
Creates a pointer and assigns it to the base address of "Hello".
pointer and &pointer[0] are the same thing.
pointer[n] takes the address of "Hello" and offsets it by the number 'n', be sure not to index of the end of the address or you will read rubbish.
So:
pointer[0] = 'H'
pointer[1] = 'e'
pointer[2] = 'l'
pointer[3] = 'l'
pointer[4] = 'o'
pointer[5] = 0
You want to access the char of char* simply use [] operator, just like arrays.
char *pointer = "Hello";
printf("%s", pointer); // ok
printf("%s", &pointer[0]); // wrong way of accessing specific element (it is same as the base address.., thus %s prints the whole thing)
Instead you're accessing the address of the first element of char* or string literal.. why!
printf("%c", pointer[0]); // use this one
Just like arrays, access the required element.
However, to get it better, notice here:
#include <stdio.h>
int main() {
char *pointer = "Hello";
printf("%s\n\n", pointer); // ok
printf("%c", pointer[0]);
printf("%p == %p\n", (void *)&pointer[0],(void *)pointer);
// cast to void * to avoid undefined behavior
// pointed out by #ex nihilo
printf("%p", pointer+1);
return 0;
}
Output:
Hello
H0x55da21577004 == 0x55da21577004
0x55da21577005
as you can see, the pointer holds the address of the first element which is: &pointer[0] thus you get the same output.

Character Pointer in C

Experts I've some doubts in this programme.
#include<stdio.h>
void main() {
char str1[] = "Hello";
char * p = "Hello", * s, * q;
p = "Bye";
printf("%s", p);
s = p;
printf("%s", s);
q = str1;
printf("\n%s", q);
}
Here p,s and q are character pointers. As we know pointers store the address of a variable and suppose if we used p=str1 then it should store the base address of array str1. Then here how p is acting like an array itself which is storing a string? I've not really understood what's character pointer. Is it not really a pointer? Because we are not using & and neither are we getting the address as an output. Please help. Thank you.
You are very much correct here:
As we know pointers store the address of a variable and suppose if we used p=str1 then it should store the base address of array str1.
Your first question:
Then here how p is acting like an array itself which is storing a string?
You can say p is acting like an array but in reality, it is just a pointer which is pointing to the base address of string str1 which is a null-terminated string.
Your second question:
I've not really understood what's character pointer. Is it not really a pointer?
A character pointer is again a pointer like the pointers to other types in C.
But there is catch here. when you do:
char a = 'A';
char *ptr = &a; // ptr points to character 'A'
Here ptr is pointer to a character.
But when you do:
char *str = "Hello";
char *ptr = str; // ptr points to first character of string str
Here ptr is pointer to a string
A point to note here is - pointer to a character is different from the pointer to a string.
In C, strings are defined as an array of characters. The difference between a character array and a string is the string is terminated with a special character ‘\0’.
So,
char str[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
char str[] = "Hello";
Both are same but there is a difference in the way they have been initialized.
Wherever in the program, we use str, this will give the base address of string "Hello". Similarly, string literals are also an array of characters with an exception that they can not be changed because the compiler may put them read-only data section.
So, if we have char *ptr = str then
ptr[0] == str[0]
ptr[1] == str[1]
.....
..... and so on
Because,
ptr[0] is *(ptr + 0) which is character at 0th location of string str and can also be written as *ptr and
ptr[1] is *(ptr + 1) which is a character at the 1st location of string str.
When we increment a pointer, it gets incremented in steps of the object size that the pointer points to. Here, ptr is pointer to char so, ptr+1 will give address of next character and *(ptr + 1) give the character at that location. That's why to the user it looks like its acting like an array.
Your third question:
Because we are not using & and neither are we getting the address as an output.
If I am getting it correctly you want to print the base address of the string, the pointer is pointing to.
In order to get the base address of string a pointer is pointing to you need to use %p. Like this:
#include<stdio.h>
int main() {
char str1[] = "Hello";
char * ptr = str1;
printf ("%s\n", str1);
printf ("%s\n", ptr);
printf ("%p\n", ptr);
printf ("%p\n", str1);
printf ("%p\n", &str1[0]);
return 0;
}
Output on my system:
Hello
Hello
0x7fff5e997b46
0x7fff5e997b46
0x7fff5e997b46
Here you can see - ptr, str and &str[0] giving same address.

Changing the value while two pointers pointing to the same location

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.

Run-time error in program

int main()
{
char *p="abcd";
while(*p!='\0') ++*p++;
printf("%s",p);
return 0;
}
I am not able to understand why the code does not run. The problem is in the statement ++*p++, but what is the problem?
P points to constant string literal *p="abcd"; by doing ++*p++ you are trying to modify string '"abcd"', for example a in string will be increment to 'b' because of ++*p that is undefined behavior (constant string can't change). it may cause a segmentation fault.
`++*p++` means `++*p` then `p++`
^
| this operation try to modify string constant
char *p="abcd";
p is pointing to a readonly segment and you can not increment p as you did here
while(*p!='\0') ++*p++;
//char *p="abcd";//"string" is const char, don't change.
char str[]="abcd";//is copied, including the '\0' to reserve space
char *p = str;
while(*p!='\0') ++*p++;
//printf("%s",p);//address pointing of 'p' has been changed
printf("%s",str);//display "bcde"
char *foo = "abcd";
char bar[] = "abcd";
Consider the differences between foo and bar. foo is a pointer that's initialised to point to memory reserved for a string literal. bar is an array with it's own memory that's initialised to a string literal; it's value is copied from the string literal during initialisation. It is appropriate to modify bar[0], etc, but not foo[0]. Hence, you need an array declaration.
However, you can't increment an array declaration; That's an operation for pointer variables or integer variables. Additionally, your loop changes where p points at, before it's printed, so you need to keep the original location of your string somewhere. Hence, you also need a pointer, or an integer declaration.
With this in mind, it might seem like a good idea to change your code to something like this:
int main()
{
char str[] = "abcd";
/* Using a pointer variable: */
for (char *ptr = str; *ptr != '\0'; ++*ptr++);
/* Using a size_t variable: */
for (size_t x = 0; str[x] != '\0'; str[x++]++);
printf("%s", str);
return 0;
}

Resources