C: pointer of char & segmantation fault - c

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.

Related

using array of chars and strdup, getting segmentation fault

Suppose i write,
char **p;
p[0] = strdup("hello");
Strdup creates a duplicate string in heap with ending character '\0'; As p is pointer to pointer of char, p[0] = strdup("hello") seems perfectly fine for me. But why am i getting segmentation fault.
Let's look at a simpler example. Suppose you say
int *ip;
ip[0] = 5;
ip is a pointer to one or more ints -- but it's not initialized, so it points nowhere, so ip[0] isn't a valid memory location, so we can't store the value 5 there.
In the same way, when you said
char **p;
p is a pointer that points nowhere. If it did point somewhere, it would point to another pointer. But it doesn't point anywhere, so
p[0] = strdup("hello");
blows up.
To fix this, you need to make p point somewhere, and specifically to memory allocated to hold one or more pointers. There are many ways to do this:
char *q;
p = &q; /* way 1 */
char *a[10];
p = a; /* way 2 */
p = malloc(10 * sizeof(char *)); /* way 3 */
or instead of using a pointer, use an array to start with:
char *p[10]; /* way 4 */
After any of those, p[0] = strdup("hello") should work.
For way 3, we would also need to check that malloc succeeded (that it dd not return a null pointer).
For ways 2 through 4, we could also set p[1] through p[9]. But for way 1, only p[0] is valid.
See also this answer to a different question for more discussion about trying to use uninitialized pointers.
There is declared an uninitialized pointer that has an indeterminate value.
char **p;
so dereferencing the pointer in this expression p[0] (that is equivalent to the expression *p) used in this statement
p[0] = strdup("hello");
invokes undefined behavior because there is an attempt to write to memory using an incorrect pointer value of the expression p[0].
You could write either for example
char *s;
char **p = &s;
p[0] = strdup("hello");
Or
char **p = malloc( sizeof( char * ) );
p[0] = strdup("hello");
That is the pointer to pointer p must point to a valid object. Thus dereferencing the pointer you will get a valid object of the type char * that will be assigned by the value returned by the call of strdup..

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.

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.

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".

Differences between pointer initializations

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.

Resources