I was thinking about pointer initialization and tried the following two cases:
#include <stdio.h>
int main(int argc, char **argv)
{
int *d;
int f;
int p;
*d = 6;
printf("%d %d %d\n", *d, f, p);
return 0;
}
This code segfaults at the line (seen in gdb):
*d = 6;
Which makes sense because I am trying store a value at a random address.
I then tried the following:
#include <stdio.h>
int main(int argc, char **argv)
{
int *d;
int f = 10;
int p = 9;
*d = 6;
printf("%d %d %d\n", *d, f, p);
return 0;
}
This runs to completion with the output:
6 10 9
If only f is initialized to 10 (p is not initialized) or vice versa, the program still completes with output
6 10 0
or
6 0 9
(p initialized). I do not understand why this works. My initial guess is that the initialization of either f or p makes space or orients memory to allow for the safe initialization of d. I also thought about stack allocations, but am still unsure.
Your first problem is in *d = 6; as you're trying to to dereference an invalid pointer.
d is not initialized (allocated memory) and it points to an invalid memory location. Any attempt to dereference that will lead to undefined behavior.
FWIW, the second code also produces UB for the same reason.
Additionally, in the first code snippet, by writing
printf("%d %d %d\n", *d, f, p);
where f and p are uninitialized automatic local variable, you're trying to read indeterminate values, which again, produces UB. This is avoided in the second snippet by explicit initialization.
In your program -
*d = 6; // writing to an invalid memory location
You leave the pointer with uninitialized value. So when you dereference it (*d), you access unauthorized location in memory, resulting in a segmentation fault.
you also try to print uninitialized local variables-
printf("%d %d %d\n", *d, f, p); // where f and p are indeterminate
Therefore , your code invokes undefined behaviour and your program give output which literally can be anything.
This code segfaults at the line (seen in gdb):
*d = 6;
Which makes sense because I am trying to give random address to a
value.
It does make sense that that segfaults, but your explanation is grossly incorrect. You are not in any way giving / or assigning an address to a value. Rather, you are attempting to store a value at an unspecified address.
It is critically important to understand the difference between d and *d. The former (as you have declared it) is a pointer that is expected to hold the address of an int. The latter is the int that d points to. If d has not, in fact, been initialized to point to an int, then evaluating the expression *d produces undefined behavior.
Undefined behavior is exactly that -- undefined. You cannot expect a similar source of undefined behavior to produce the same actual behavior in other circumstances, and you cannot even rely on the behavior to manifest an obvious indication of brokenness. Anything can happen, including, in principle, what the programmer wanted to happen.
Declaring a pointer variable does not automatically cause any storage to be allocated. There are any number of ways you could initialize d, but one would be
d = &f;
You need to Allocate your memory with malloc()
this work:
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv)
{
int *d;
int f = 10;
int p = 9;
d = /*(int *)*/malloc(sizeof(int) * 1);
if (!d)
exit(-1);
*d = 6;
printf("%d %d %d\n", *d, f, p);
free(d);
return 0;
}
Related
Please explain (reason for the output) what happens as a result of running the two segments of code. Please explain their difference too. There are two versions of setArr(int, int) as explained below...
#include <stdio.h>
void setArr(int, int);
int *arr[10]; // array of 10 int pointers
int main(int argc, char *argv[]) {
int i;
setArr(0, 0);
setArr(1, 100);
setArr(2, 200);
setArr(3, 300);
setArr(4, 400);
for (i = 0; i < 5; i++)
printf("arr[%d]: %d\n", i, *arr[i]); /* should be 0,100, 200,300,400 */
return 0;
}
Versions of setArr
Version A
void setArr(int index, int v) {
int i = v;
*arr[index] = i;
}
Output: Segmentation fault (core dumped)
Version B
void setArr(int index, int v) {
int i = v;
arr[index] = &i;
}
Output:
arr[0]: 400
arr[1]: 32748
arr[2]: 32748
arr[3]: 32748
arr[4]: 32748
I presume the values from running Version B are just random values.
I am fairly new to pointers I have knowledge in Java, so please explain it as beginner friendly as you can :)
You are hitting a lot of undefined behavior scenarios, but I will explain what is likely happening.
arr is an array of 10 pointers to integers.
int * arr[10]; // array of 10 int pointers
And when declared as a global variable, all of those pointers are going to be zero-initialized - so hence, it's an array of 10 NULL pointers.
So this line in version A, is dereferencing the address at arr[index]:
* arr[index] = i;
Is effectively saying this:
*(NULL) = i;
And that will certainly crash consistently.
In Version B, you have it as:
int i = v;
arr[index] = &i;
So now you are correctly assigning a pointer to a slot in the array. However that address getting assigned is to a local stack variable, i, which goes out of scope as soon as the function returns. So when you print the value at that address, it's most certainly been clobbered from other calls writing on top of the stack. (Or technically this "undefined behavior" of accessing a memory address of a stack variable that has gone out of scope.)
Better:
void setArr (int index, int v){
arr[index] = malloc(sizeof(int));
*arr[index] = v;
}
The above allocates memory for the address that you want to copy that value into. You're on your own for how to free that memory.
Alternatively:
Just declare arr as an array of integers instead of pointers:
int arr[10];
void setArr (int index, int v){
arr[index] = v;
}
And then print normally without the * deference thing on arr.
printf("arr[%d]: %d\n", i, arr[i]);
Version A says "the contents of an undefined pointer equals i" - undefined behavior = crash. Basically you are trying to write to some unknown location in memory.
Version B says "Some pointer = some address" - still undefined behavior as &i goes out of scope, but it is still an address and so it "kind of works". Here you are writing to "good" memory locations, but reading from bad ones.
in first case, you have defined the "array of pointers" to integer. They are not integer pointers. Either you will have to allocate memory (preferably using melloc/calloc functions) before storing any value to them OR you can define the array of integer like this:
int (*a)[10]
The following link may show you some idea about it: Difference between *ptr[10] and (*ptr)[10]
In second case, you are saving the address of integer into integer pointer, which is ok, but int i is local variable to function setArr(). This will therefore, the value of int i will be dereferenced every time the function setArr() exits. Therefore you are getting undefined behavior for 2nd case. Either you can use static int i OR use global variable (not preferred) OR use pointer to integer assignment.
This question already has answers here:
How to change a variable in a calling function from a called function? [duplicate]
(3 answers)
Closed 4 years ago.
void change_it(int[]);
int main()
{
int a[5],*p=1;
void change_it(int[]);
printf("p has the value %u \n",(int)p);
change_it(a);
p=a;
printf("p has the value %u \n",(int)p);
return 0;
}
void change_it(int[]) {
int i=777, *q=&i;
a = q; // a is assigned a different value
}
For starters, when you initialize p, you're giving a pointer the value of 1, when it needs a memory location. NULL uses 0, but that doesn't mean you can -or should- just assign integer values to pointers.
Just as an fyi, you can cast the value of 1 like this:
int a[5], *p = (int *) 1;
There's like -2 reasons for doing this, though, the -1th reason being that the minimal type safety that C provides should be respected, and the -2th being that it makes the code hard to understand for other people.
I'm going to assume what you meant to do was not declare a pointer with an address value of 1 though, and say you meant to declare a pointer that holds a value of 1. Unless you have another variable that holds the value of 1 already, you're going to have to first dynamically allocate the pointer, then set its value.
int* p = malloc(sizeof(int));
*p = 1;
If you had another variable to use, you could instead create the pointer on the stack rather than dynamically allocating it, like this:
int* q;
q = p;
Now, calling the same print function on both would yield this:
printf("p has the value %d\n", *p);
printf("q has the value %d\n", *q);
Output:
p has the value 1
q has the value 1
Addressing your main problem, you need to name the parameter in the change_it function, for example:
void change_it(int arr[])
Your program needs the parameter to be named, otherwise it has no idea of knowing you're trying to reference the array. The a variable you reference in the function is not bound to anything; the compiler will know be able to deduce what you're talking about.
Also, you don't need to redeclare the function prototype in your main function. The reason this is not a compiler error is that you can have as many declarations as you want, but only one definition. Again though, there's no reason to do this.
Another fyi, you don't have to name the parameters in your function prototypes, but it's good practice to both name them and be consistent with the names between the prototypes and the actual implementations so that people reading your code understand what's going on.
Also, you're using the %u specifier for the printf function, when you're not actually using unsigned decimal numbers. You're using signed decimals so you should use %d.
Lastly, your change_it function commits one crucial error preventing it from correctly changing the value of the passed-in array properly: you're setting the array that you passed in to the value of q.
Look at the function in your original code closely (pretend you named the input array a, as it looks like you mean to). You first declare an integer variable i and set its value to 777. Then, you create an integer-pointer variable q on the stack and correctly set its value to i. Note: You're not setting q to the value of i, but rather the address of i.
Why does this small but significant distinction matter? When you set a to q in the next line, you're changing the address of the array, specifically the first element of a five-element integer array, to point to the address of an integer variable. This is bad for a few reasons. First, the array is five integers long, but now it points to a single element. If and when you try to access elements 2-5, you'll get either meaningless garbage or a segmentation fault for trying to access memory you don't own. Even worse, the variable i is allocated on the stack, so when the function change_it exists, the function's data will be popped off the stack, and trying to access the address of i will yield either garbage or a segmentation fault for trying to access memory you don't own. See a pattern?
I'm not really sure how to correct this code, as I'm not sure what you were trying to accomplish, but correcting the aforementioned errors, your code now looks something like this:
#include <stdio.h>
void change_it(int arr[]);
int main()
{
int a[5];
int *p = a; // Equivalent to int *p = &a[0];
printf("a address: %p\n", a); // Should be equal to p
printf("p address: %p\n", p); // Should be equal to a
a[0] = 1;
printf("a[0] = %d\n", a[0]); // 1
printf("p has the value %d\n", *p); // 1
change_it(a);
p = a;
printf("a address: %p\n", a);
printf("p address: %p\n", p);
printf("a[0] = %d\n", a[0]);
printf("p has the value %d \n", *p);
return 0;
}
void change_it(int arr[])
{
int i=777;
arr[0] = i;
// Could be just:
// arr[0] = 777;
}
Output:
p address: 0x7fffc951e0b0
a[0] = 1
p has the value 1
a address: 0x7fffc951e0b0
p address: 0x7fffc951e0b0
a[0] = 777
p has the value 777
Note: Your memory address can and probably will be different from these, all it matters is that p and a are equal in both.
Anyways, hope this helps. Let me know if you have any questions.
Alright, you I believe do not have basic understanding of a function: First lets start with declaration and definition:
void change_it(int[]); // THIS IS DECLARATION
int main ()
{
void change_it(int[]); // THIS IS DECLARATION (duplicate and unnecessary
....
}
void change_it(int[] a) // THIS IS DEFINITION
{
int i=777, *q=&i;
a = q; // a is assigned a different value
}
declaration of the function only needs (you can put parameter name for readability) a parameter type, where as definition has to have name of the parameter because in definition parameters are local variables.
printf("p has the value %u \n",(int)p);
This will print the address of p not the value of p. So this should be
printf("p has the value %u \n", *p);
And finally we get to the body of a function. Where you are depending on somthing that have been locally assigned and putting it back into parameters
void change_it(int[] a)
{
int i=777, *q=&i;
a = q; // a is assigned a different value
}
so q is pointer and you are assigning address of local variable i to it. Well what happens when your program exists the function? i might disappear thus loosing its values and its address, which is assigned to q which means q is loosing its variable and value, and which is assigned to a which might loos its variable because it is pointing to i in your function.
This part here:
int a[5],*p=1;
void change_it(int[]); // Here, doesn't compile
printf("p has the value %u \n",(int)p);
That statement isn't just valid, as far as I know, you can't declare a function inside another function in C.
Also:
void change_it(int[]) // Here, an error
{
int i = 777, *q = &i;
a = q;
}
This function needs an argument, but you supplied only its type (being int[]),
void change_it(int a[]) fixes the problem
Your program does not compile and produce warnings. It would not work as you intended.
1) p is a pointer. To access value which it points to you have to dereference it using * dereference opearator.
2)
void change_it(int[]);
is not needed in the body of main.
3)
the invocation of change_it() seems to have no effect
If you want to change a[0] element inside the function change_it name the passing parameter to a and dereference the q pointer,
The working program may look as this:
#include <stdio.h>
void change_it(int a[]);
int main()
{
int a[5] = {0}; // init all element of `a` to `0`
int *p; // declare int pointer
p = a; // p point to array `a`
// print the first element of array `a`
printf("a[0] has the value %d \n",(int)*p);
// call function change_it, pass `a` as the argument
change_it(a);
printf("a[0] has the value %d \n",(int)*p);
return 0;
}
// change the value of the first element of array `a` to 777
void change_it(int a[]) {
int i=777, *q; // declare int i and pointer
q = &i; // pointer `q` points to the `i` now
a[0] = *q; // a[0] is assigned value = 777;
}
Output:
a[0] has the value 0
a[0] has the value 777
The following code seems to work. gcc 5.2.1 on linux didn't give any warning.
I am a newbie to C. I got this working by writing down what the & and * operators do at each line with English sentences and trial and error.
There are two things that I am not sure.
The initial value of p0 in line A is unpredictable. Yet, line E assigns a value to the address specified by the value of the variable p0 in main. Will this cause any problem? If so, how to fix that?
The code use so many *, like *** in line C. Can it use less * without getting warning from gcc?
Thank you.
#include <stdlib.h>
#include <stdio.h>
void* f(int*** ptr_p) //C
{
int** p = *(ptr_p); //D
*p = malloc(8); //E
*(*p) = 200; //F
(*p)[1] = 4; //G
}
int main(void)
{
int** p0; //A
f(&p0); //B
printf("%d, %d\n",*(*p0), (*p0)[1]);
free(*p0); //H
}
In case if you want to see the English sentences, here they are.
Warning: I am a newbie in C, and I don't know if they are all correct.
Line [A] int** p0;
The value of p0 is unpredictable.
Line [B] f(&p0);
&p0 is address of variable p0. f(&p0) means to call function f and assign &p0 to the 1st argument of the function.
Line [C] void* f(int*** ptr_p)
Line B assigns &p0 to ptr_p. This means the value of ptr_p is now equal to the address of variable p0 in the main function.
Line [D] int** p = *(ptr_p);
*(ptr_p) means the value at an address specified by the value of ptr_p, interpreted as an address. Value of ptr_p is address of variable p0 in the main function, as described in Line C. So, *(ptr_p) is value of variable p0 in the main function.
p = *(ptr_p); means assign value of p0 in the main function to value of p
Line [E] *(p) = malloc(8);
*(p) means value at an address specified by the value of p. Value of p is value of the p0 variable in main, as described in Line [D]. Then, *(p) means value of the address specified by the value of the p0 variable in main().
malloc(8) reserves 8 bytes in memory, and return the address of the first of the 8 bytes.
The whole line means to assign the address of the first of these 8 bytes as the value of the address specified by the p0 variable in main().
Line [F] *(*p) = 200;
Line [G] (*p)[1] = 4;
(p)[1] means *(p + 1)
(*p)[1] means *(*p + 1)
Yes, line E is a problem. Actually, you are already in trouble at line D, because you read the (undefined) value of p0. This is forbidden in C; it is part of the dreaded undefined behavior, which means that all bets are off and the compiler is legally allowed to output anything it wants: a binary that crashes, or prints "Hello world!", you name it.
You correctly saw that p0 should point to an int * buffer before you can write in that buffer. However, there is no need for this extra level of indirection. p0 can be an int *:
#include <stdlib.h>
#include <stdio.h>
void f(int** ptr_p) //C
{
*ptr_p = malloc(sizeof(int) * 2); //E
(*ptr_p)[0] = 200; //F
(*ptr_p)[1] = 4; //G
}
int main(void)
{
int* p0; //A
f(&p0); //B
printf("%d, %d\n", p0[0], p0[1]);
free(p0); //H
return 0;
}
One last thing: malloc could fail and return NULL; a robust program would check that.
You have more stars that you need: the fewer the better, so I have simplified your program.
#include <stdio.h>
#include <stdlib.h>
int *f(int size) // returns a pointer
{
int *p; // define a pointer
p = malloc(size); // allocate memory to it
if(p == NULL) { // check the result
exit(1); // emergency exit
}
*p = 200; // put a value at p[0];
p[1] = 4; // put a value at p[1];
return p; // return the pointer
}
int main(void)
{
int *p0; // pointer as yet has no value assigned
p0 = f(2 * sizeof *p0); // get memory for 2 ints and initialise it
printf("%d, %d\n", *p0, p0[1]); // show the two ints assigned
free(p0); // release the memory
return 0; // end of program
}
Program output:
200, 4
Apart from fewer stars, there are two main changes to your program
The function returns a pointer directly. Setting it via an argument requires one more star.
The amount of memory requested is for two elements of the data type, not "hard coded".
Also you are correct in thinking there is more than one way you can access an array based on a pointer.
If I have a 2d array B defined as :
int B[2][3] = {{1,3,5},{2,4,6}};
Is int **p = B same as int (*p)[3] = B ?
int **f = B; printf("%d ",*f+1);
gives 5 as output while printf("%d ",*f) gives 1 as answer. Why
is that happening?
printf("%d ",**f);
returns a segmentation fault! Why?
No. int **p = B; is an error. (Both a compilation error, and a logical error). An int ** must point to an int *. However, there are no int * stored in B. B is a group of contiguous ints with no pointers involved.
int **f = B; must give a compilation error. The behaviour of any executable generated as a result is completely undefined.
See 2.
To explain why you might be seeing 1 and 5. (The C standard does not define this, but your compiler bulls on ahead anyway). Probably your compiler treats the line as
int **f = (int **)B;
Then the expression *f will read bytes from the storage of B (which actually hold ints) and pretend that those are the bytes that make up a pointer representation. This is further undefined behaviour (violation of strict-aliasing rules). Probably the result of this is that *f is a pointer to address 0x00000001.
Then you print a pointer by using %d, causing further undefined behaviour. You see 1 because your system uses the same method for passing int to printf as it does to pass int *.
When you add 1 to (int *)0x00000001, you get (int *)0x00000005, because incrementing a pointer means to point to the next element of that type.
When you dereference this pointer, it causes a segfault because that address is outside of your valid address space.
1) Is int **p = b same as int (*p)[3] = b ? - No. int **p = b is an error.
Because here int **p is a pointer to pointer to an integer, but int (*p)[3] is pointer to an array of 3 integers!
2) int **f = B; It is an error, May results in Undefined behavior!
3) printf("%d ",**f); - It is same as (2). int **f = B; is error, so Undefined behavior!
NOTE: To avoid this type of error enable some warning flags in compiler option and try!
In this answer, the author discussed how it was possible to cast pointers in C. I wanted to try this out and constructed this code:
#include <stdio.h>
int main(void) {
char *c;
*c = 10;
int i = *(int*)(c);
printf("%d", i);
return 1;
}
This compiles (with a warning) and when I execute the binary it just outputs bus error: 10. I understand that a char is a smaller size than an int. I also understand from this post that I should expect this error. But I'd really appreciate if someone could clarify on what is going on here. In addition, I'd like to know if there is a correct way to cast the pointers and dereference the int pointer to get 10 (in this example). Thanks!
EDIT: To clarify my intent, if you are worried, I'm just trying to come up with a "working" example of pointer casting. This is just to show that this is allowed and might work in C.
c is uninitialized when you dereference it. That's undefined behaviour.
Likewise, even if c were initialized, your typecast of it to int * and then a dereference would get some number of extra bytes from memory, which is also undefined behaviour.
A working (safe) example that illustrates what you're trying:
int main(void)
{
int i = 10;
int *p = &i;
char c = *(char *)p;
printf("%d\n", c);
return 0;
}
This program will print 10 on a little-endian machine and 0 on a big-endian machine.
These lines of code are problematic. You are writing through a pointer that is uninitialized.
char *c;
*c = 10;
Change to something like this:
char * c = malloc (sizeof (char));
Then, the following line is invalid logic, and the compiler should at least warn you about this:
int i = *(int*)(c);
You are reading an int (probably 4 or 8 bytes) from a pointer that only has one byte of storage (sizeof (char)). You can't read an int worth of bytes from a char memory slot.
First of all your program has undefined behaviour because pointer c was not initialized.
As for the question then you may write simply
int i = *c;
printf("%d", i);
Integral types with rankes less than the rank of type int are promoted to type int in expressions.
I understand that a char is a smaller size than an int. I also understand from this post that I should expect this error. But I'd really appreciate if someone could clarify on what is going on here
Some architectures like SPARC and some MIPS requires strict alignment. Thus if you want to read or write for example a word, it has to be aligned on 4 bytes, e.g. its address is multiple of 4 or the CPU will raise an exception. Other architectures like x86 can handle unaligned access, but with performance cost.
Let's take your code, find all places where things go boom as well as the reason why, and do the minimum to fix them:
#include <stdio.h>
int main(void) {
char *c;
*c = 10;
The preceding line is Undefined Behavior (UB), because c does not point to at least one char-object. So, insert these two lines directly before:
char x;
c = &x;
Lets move on after that fix:
int i = *(int*)(c);
Now this line is bad too.
Let's make our life complicated by assuming you didn't mean the more reasonable implicit widening conversion; int i = c;:
If the implementation defines _Alignof(int) != 1, the cast invokes UB because x is potentially mis-aligned.
If the implementation defines sizeof(int) != 1, the dereferencing invokes UB, because we refer to memory which is not there.
Let's fix both possible issues by changing the lines defining x and assigning its address to c to this:
_Alignas(in) char x[sizeof(int)];
c = x;
Now, reading the dereferenced pointer causes UB, because we treat some memory as if it stored an object of type int, which is not true unless we copied one there from a valid int variable - treating both as buffers of characters - or we last stored an int there.
So, add a store before the read:
*(int*)c = 0;
Moving on...
printf("%d", i);
return 1;
}
To recap, the changed program:
#include <stdio.h>
int main(void) {
char *c;
_Alignas(in) char x[sizeof(int)];
c = x;
*c = 10;
*(int*)c = 0;
int i = *(int*)(c);
printf("%d", i);
return 1;
}
(Used the C11 standard for my fixes.)