C program: pointer and pointer of string - c

This is the code that make me confused.
static char *s[] = {"black", "white", "pink", "violet"};
char **ptr[] = {s+3, s+2, s+1, s}, ***p;
p = ptr; // p point to the address of (s+3), so "violet"
++p; // p point to "pink"
printf("%s", **p+1); // I though it print "pink" but answer is "ink", I'm not sure about the sequence of ** and +, which executes first and how is this one begins from "i"?

After ++p, p does not point to "pink". It points to ptr[1], and ptr[1] points to s[2], and s[2] points to the first character of "pink".
*p is ptr[1], and **p is s[2]. So **p + 1 is &s[2][1], i.e. the "i" in "pink".
It is like:
char *ptr = **p; // ptr points to the 'p' in "pink"
printf("%s", ptr + 1);

static char *s[] = {"black", "white", "pink", "violet"};
The above statement defines s to be an array of characters and initializes its elements with pointers to the first element of the string literals enclosed in braces. static means the array s has internal linkage and its lifetime extends across the entire program run.
char **ptr[] = {s+3, s+2, s+1, s}, ***p;
The above statement defines ptr to be an array of objects of type char **, i.e., pointer to pointer to characters. It also defines p of type char ***, i.e., a pointer to a pointer to a pointer to a character. It initializes ptr with pointers to elements of the array s.
Therefore, ptr[0] points to s[3], ptr[1] points to s[2] and so on. The below two statements are equivalent. This is because the array ptr decays (evaluates) to a pointer to its first element.
p = ptr;
// the above is equivalent to
p = &ptr[0];
++p; // makes p point to the next element of ptr
The side effect of executing the above statement is to increment p, i.e., make it point to the next element which is ptr[1].
**p+1
Indirection operator * has higher precedence. Therefore, **p is evaluated first. Since p is pointing to ptr[1], *p evaluates to ptr[1]. Now ptr[1] is pointing to s[2], therefore **p evaluates to s[2]. s[2] is pointing to the first element of the string literal "pink". This means **p + 1 points to the next element, i.e, 2nd element which is 'i'.
printf("%s", **p + 1); // prints ink
// equivalent to
printf("%s", "pink" + 1); // prints ink
// equivalent to
printf("%s", &"pink"[1]); // prints ink

**p points to pink (i.e. **p == s[2]). Incrementing that pointer (**p) + 1 will make it point to the i in pink, so printf will print ink. Elementary. :)
The rule of thumb is that if you feel the need for declaring a triple-pointer, you are doing something wrong.

*p gives ptr[1]
**p gives value stored at s+2 i,e "pink" and it points to character p
now **p+1 gives the string ink

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.

why name of string contain address of itself in c

How is it possible, name of string contains address of string - YES ok
but its (name of string) address should be different, but it is the same
NOT only that , *str gives the first character - that's ok
but *str is nothing but value at(6356737), in this code
but that itself is equal to 6356737 and not 'f'(which is nothing but str[o])
int main()
{
char str[] = "fdsgugreui";
printf("\nstr=%u,&str=%u : *str = %c\n",str,&str,*str);
int i=0;
while(str[i] != '\0'){
printf("\n&str[%d] =%u : str[%d] = %c\n ",i, &str[i], i, str[i]);
++i;
}
return 0;
}
//result...
str=6356737,&str=6356737 : *str = f
&str[0] =6356737 : str[0] = f
&str[1] =6356738 : str[1] = d
&str[2] =6356739 : str[2] = s
&str[3] =6356740 : str[3] = g
&str[4] =6356741 : str[4] = u
&str[5] =6356742 : str[5] = g
&str[6] =6356743 : str[6] = r
&str[7] =6356744 : str[7] = e
&str[8] =6356745 : str[8] = u
&str[9] =6356746 : str[9] = i
Process returned 0 (0x0) execution time : 0.150 s
Press any key to continue.
I cannot understand why!
str is the char array which decays into a pointer to the first element of the char array - which is same as &str[0].
Note that value-wise str and &str are the same but their type is different. str decays into pointer - so it becomes char* but the second one is char(*)[11] (note when you pass array name as operand of & it won't decay into pointer) which is a pointer to an array object.
The correct way to print address is printf("%p",(void*)str); and this also will be same for other pointer variables.
str[0] is the content of the array str at the position 0. That's it - it has nothing to do with having an address, It is a char. In your case str[0] is nothing but 'f'.
What is array decaying?
So in most situations, the array is converted to the pointer to the first element. This is array decaying. Notice the case here str is an array of chars - when we use str in printf it is converted to a pointer to the first element of itself which is address of str[0] and the pointer contains that value. This explains why you get the value of &str[0] when you printed str.
There are a few exceptions to array decaying:
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.
The fun part is &str here you see it is an operand to & address of operator - this is an exception where the decaying won't happen. So &str is a pointer to an array object. The type is char (*)[]. And yes, as you sae it will be of the same value as that of str or &str[0] but it's type is completely different.
What is char(*)[SIZE]?
It is denoting a pointer to an array of chars which has the size of SIZE. There are SIZE elements in the array.
Is char (*p)[SIZE] same as char* p[SIZE]?
Noo. It is not. First one is a pointer to an array of chars which has SIZE number of elements.
char* p[] is an array of char*-s. These are not the same. The first one is denoting a single pointer and the second is an array of pointers.
Another thing is - for pointers there are two things that matter
The value of the pointer.
The type of the pointer.
The second one dictates how the pointer arithmetic will be depending on the size of the type of object it points to. In here also you saw that &str and str has same value but not the same type. You will be surprised if you see these statement and print it.
printf(" &str+1 = %p str+1 = %p\n",(void*)(&str+1),(void*)(str+1));
Hint: The first one &str is a pointer to an array. The second is pointer to a char.

C Pointer for 2-dimensional Array

Already declared is an array such as:
char ma[10][20];
The address of a specific element is gotten using:
p = &ma[1][18];
Which element will p point to after p++; ?
Adding 1 to a address of member of array, get the address of the next member. since p is the address of ma[1][18], which is member of the array ma[1], p+1 is the address of ma[1][19]. (And of course, p++; is like p=p+1;)
Edit: I assumed, of course, that p is char*. If it's something else, the answer can be other.
p++ yields &ma[1][19]
Here is the explanation:
char ma[10][20];
char *p = &ma[1][18];
p value is &ma[1][18] which is equal to *(ma + 1) + 18.
So p++ value which is equal to p + 1 is equal to (*(ma + 1) + 18) + 1 equal to *(ma + 1) + 19 which is equal to &ma[1][19].
You don't specify the type of p; assuming it's char *, then p++ will advance it to ma[1][19] (1 char).
Here are a couple of variations:
char (*p)[20] = &ma[1];
In this case, p is a pointer to a 20-element array of char, initialized to point to ma[1]; executing p++ will advance p to point to ma[2] (20 chars).
char (*p)[10][20] = &ma;
In this case, p is a pointer to a 10-element array of 20-element arrays of char, initialized to point to ma; executing p++ will advance p to the next element immediately following ma (200 chars).

pointers increment in c

#include<stdio.h>
int main()
{
static char *s[]={"black","white","pink","violet"};
char **ptr[]={s+3,s+2,s+1,s},***p;
char a[]={"DEAD"};
p=ptr;
++p;
printf("%c\n",a[0]);
printf("%s\n",*s); //black
printf("%s\n",*s+1); //lack
//printf("%s\n",s+1);
printf("%s\n",s[0]);//black
printf("%s\n",s[1]);//white
printf("%s\n",s[2]);//pink
printf("%s\n",s[1]);//violet
printf("%s\n",s[1]+1);//hite
printf("%s\n",s[1]+6);//pink
printf("%s\n",**p+1); // how does this prints ink
return 0;
}
output:
D black lack black white pink white hite pink ink
please help to understand
so, p is a pointer to a pointer to a string, which basically is a pointer to a char.
p itself points to the first element of the ptr array; after p++ it points to the second, which is s+2.
s+2 points to the third element in the s array, which is "pink"
these are the two levels od dereferencing performed by **p
now, **p points to the first character of "pink", thus **p+1 points to the 'i'
now, printf takes the pointer to the i and prints everything until the next null byte, resulting in "ink" being printed to your console.
I assume you have no problem with lines I haven't directly copied
printf("%s\n",*s+1); //lack
*s+1 is the same as (*s) + 1
printf("%s\n",s[1]+6);//pink
s[1]+6 is the same as (s[1]) + 6. s[1] has type char*, so s[1]+6 points 6 characters to the right. But it's illegal to do that: s[1] only points to 6 valid characters. You just had (bad) luck that your program didn't crash.
printf("%s\n",**p+1); // how does this prints ink
approximately the same things go for **p+1 :)
You have to understand pointers.
s[0] is exactly the same as *s.
If you have s[0]+1, it points one char further than s[0].
s[1] is the same as *(s+1), but it is completely different from *s+1, which is the same as s[0]+1.
You have to draw arrows on a blackboard.
p = ptr;
++p; /* p now points to the second element of ptr "s+2" */
/* s+2 points to the third element of s "pink" */
/* **p+1 will point to the second character of "pink", thus "ink"; essentially **(s+2)+1 */

Can anybody explain how its printing output as "ink"

I am new to pointers in C. I know the basic concepts. In the below code, why is it printing the "ink" as its output?
#include<stdio.h>
main()
{
static char *s[]={"black","white","pink","violet"};
char **ptr[]={s+3,s+2,s+1,s},***p;
p=ptr;
++p;
printf("%s",**p+1);
}
Thanks
Let's trace it:
ptr = {pointer to "violet", pointer to "pink", pointer to "white", pointer to "black"}
p = ptr --> *p = pointer to "violet"
++p --> *p = pointer to "pink"
This implies that:
*p = {'p','i','n','k','\0'}
Which means:
**p = 'p'
**p + 1 = 'i'
so **p + 1 is a pointer to this string: {'i', 'n', 'k', '\0'}, which is simply "ink".
s is an array of char * (which represent strings).
ptr is an array of pointers to pointers (pointing to the values of s, which are pointers to strings)
p is set to point to ptr[0] (which is a pointer to s[3] or "violet")
p is incremented to point to ptr[1], which points to s[2] or "pink"
In the printf statement p is dereferenced twice. The first deref is a pointer to s[2], the second deref gets you the value of s[2] - "pink". The +1 shifts the pointer to the start of "pink" on by one char, so printing from here to the end of the string will give you "ink".
I'd advise that you work backwards from what you know was printed (the 'ink' in 'pink') and see where the different variables must be pointing for that to happen.
Remember that an array can be viewed as a pointer to its first element and that a string can similarly be viewed as a pointer to its first character.
static char
*s[]={"black","white","pink","violet"};
In the above statement you are initialize.
char **ptr[]={s+3,s+2,s+1,s}
In the above statement you are assign pointer s value to ptr
value. And declare a triple pointer.
p=ptr;
In the above statement you assign the double pointer address to
triple pointer.
++p;
In the above statement you increment the triple pointer value. So
that time it point to "pink".
But you are print the **p+1. That time it will print only "ink".
If you print **(p+1), that time it
will print "white". Because in the
initialization of double pointer you
initialize the "s+2". So that time it
will points to the "white".

Resources