C Indexing into double pointer to array causes crash - arrays

I have the following simplified code to allocate space for and assign values to an array from another function, passed in by a pointer to the array. A crash is caused when indexing into the dereferenced pointer:
void foo(int **arr) {
int num_elements = 3;
*arr = malloc(num_elements*sizeof(int));
for(int i=0; i<num_elements; i++){
*arr[i] = i; // crashes here
}
}
int main(){
int *main_arr = NULL;
foo(&main_arr);
// Doesn't get here
for(int i=0; i<3; i++)
printf("%d ", main_arr[i]);
printf("\n");
return 0;
}
I'm expecting the output 0 1 2 , but instead I see Segmentation fault (core dumped). The logic of what I'm doing seems sound, so I don't know what to do about it.

The problem turned out to be an ambiguity: while the logic of the code was sound, on the line that was crashing I interpreted to mean "dereference, then access the ith element", but the compiler evidently interpreted to mean "access the ith element, then dereference". Indeed, using parenthesis to explicitly state my intent solved the problem: Changing to
for(int i=0; i<num_elements; i++)
(*arr)[i] = i
produces the desired 0 1 2 output. Turns out that syntax is important!
Edit: As #JonathanLeffler pointed out, "ambiguous" was a poor word choice, as it's defined behavior that * has a lower precedence than []

Related

Dereferencing a pointer in a 'for' loop initializer creates a segmentation fault

I'm having a problem using pointers in a for loop. In my for loop initializer, I dereference an int pointer and give it a value of '0'. When I use that dereferenced pointer in the loop I get a segmentation fault, and I don't understand why. I am using Code::Blocks and the C GNU GCC compiler.
Looking at the watch window I can see that during the for loop the variable has a random number.
It seems that the dereferenced pointer loses scope during the for loop.
The code:
#include <stdio.h>
int main(void)
{
int val = 0;
int *p = NULL;
int answer = 0;
p = &val;
*p = 1; // This dereferences and sets to one successfully
for (int i=3, (*p)=0 ; i>=0; i--) // Here *p is a random number
{
printf("do stuff");
(*p) += 1; // Here it causes a segmentation fault
}
answer = *p;
}
I thought that there would be no problems using a pointer the way I am.
Take a close look here:
for (int i=3, (*p)=0 ; i>=0; i--)
In the first part of the for you're defining a new pointer variable named p which shadows the p defined earlier and initializing it to NULL. You then dereference the NULL pointer in the loop which causes the segfault.
You can't have both a variable definition and an assignment to an existing variable together like that, so move the assignment of *p to before the loop:
*p = 0;
for (int i=3; i>=0; i--)
Or you can define i outside of the loop:
int i;
for (i=3, (*p)=0 ; i>=0; i--)
You could squeeze these together by abusing the comma operator:
for (int i=(*p=0,3) ; i>=0; i--)
Here the assignment to p happens as part of the initializer for i so it doesn't declare a new variable. But I wouldn't recommend this as it would make your code more difficult to read and understand.
You are declaring a completely new variable called p:
for (int i=3, (*p)=0 ; i>=0; i--)
This is the same as:
for (int i=3, *p=0 ; i>=0; i--)
So you are creating an int i and an int *p, which points to address 0. This is not the same p as the one defined previously. It just shadows it. So when you dereference it, you get the segfault.
Tip: Use -Wshadow to get a warning when a variable shadows another one.
[] $ gcc main.c -Wshadow
main.c: In function ‘main’:
main.c:13:21: warning: declaration of ‘p’ shadows a previous local [-Wshadow]
13 | for (int i=3, (*p)=0 ; i>=0; i--) // Here *p is a random number
| ^
main.c:6:10: note: shadowed declaration is here
6 | int *p = NULL;
| ^
https://coliru.stacked-crooked.com/a/5de37f53cf0b094d

Making an array using pointers in c

I'm new to using c and I'm trying to make a program that makes an array using pointers,
#include <stdio.h>
int main()
{
int *i;
scanf("%d",i);i++;
while(1){
scanf("%d",i);
if(*i==*(i-1)){
break;}
printf("%d\n",*i);
i++;
}
return 0;
}
I Keep getting this error
Command failed: ./a.out
Segmentation fault
I think you want to create an array and read data to it and later display it using pointers dynamically.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *A, n;
printf("\n Enter the size of array : "); // Reading the size of array
scanf("%d",&n);
A = (int*) malloc(sizeof(int) * n); // Allocating memory for array
int i = 0;
for(i = 0; i < n; i++) // Reading data to array
scanf("%d", (A+i));
// Operations on array
for(i = 0; i < n; i++) // Printing array
printf("%d ", A[i]);
return 0;
}
Hope this help.!!
just a bit of explanation here.
You are declaring your i variable as a pointer here:
int *i;
The pointer does not point anywhere and contains a random value. The following operation tries to write an integer in the memory pointed by the pointer. Since it points to an undefined location, the result of this operation is unpredictable. It can crash, or can write in a place of memory which could create unexpected behavior later, or just work. In any case it causes memory corruption.
scanf("%d",i);i++;
The i++ statement actually increases the value of the pointer so that it points to the next place in memory, which would also be invalid. And so on.
Depending on the purpose of your program you can work around this issue in multiple ways. i.e. if you need just a single integer to work with , you can do the following:
int i;
scanf("%d", &i); // use an address of 'i' here
...
printf("%d", i);
now you can use the 'i' in normal arithmetic operations then. Or if you need an array of integers, you can do the followig:
int i = 0;
int a[mysize];
scanf("%d", &a[i]);
i++; // do not forget to check 'i' against 'mysize'
...
printf("%d", a[i]);
or have 'i' as a pointer:
int a[mysize];
int *i = a;
scanf("%d", i);
i++; // do not forget to check 'i' against 'mysize'
...
printf("%d", *i);
or even have the array allocated in memory by malloc, as this:
int *a = malloc(sizeof(int) * mysize);
int *i = a;
scanf("%d", i);
i++;
...
printf("%d", *i);
Note, that at some point you would need to free the memory in the last example. So, you'd better keep the pointer to the beginning of the array to be able to do free(a);
edits prefixed with ##
after cleaning up the code formatting:
to consistently indent the code
so it follows the axiom: only one statement per line and (at most) one variable declaration per statement.
Then it is obvious that the code contains undefined behavior. (see the ## comments in the code)
## each of the statements containing undefined behavior can cause a seg fault event.
#include <stdio.h>
int main( void )
{
int *i; ## uninitialized pointer declared
scanf("%d",i); ## accessing random memory I.E. undefined behavior
i++;
while(1)
{
scanf("%d",i); ## accessing random memory I.E. undefined behavior
if(*i==*(i-1)) ## reads two consecutive integers using uninitialized pointer I.E. undefined behavior
{
break;
}
printf("%d\n",*i); ## reads integer from memory using uninitialized pointer I.E. undefined behavior
i++;
}
return 0;
}
The undefined behavior, from accessing of memory that the program does not own, is why the seg fault event occurs.

What's the meaning of p = (int(*)[3])malloc(3*sizeof(*p));

#include<stdio.h>
#include<stdlib.h>
int main()
{
int i, j;
int(*p)[3];
p = (int(*)[3])malloc(3*sizeof(*p));
for(i=0; i<3; i++)
{
for(j=0; j<3; j++)
printf("%d", p[i][j]);
}
return 0;
}
p is a pointer to an array of 3 integer then why it is behaving as a 2D array
It is a completely superfluous cast that only adds clutter. Or in case of C++ it is needed, but you should never be using malloc in C++...
p is an array pointer to an array of type int [3]. *p is an array and therefore 3*sizeof(*p) gives the size of 3 such arrays, 3*3*sizeof(int). So the code allocates an array of arrays - a 2D array.
p is set to point at the first element of that array. p[i] is pointer arithmetic on an array pointer and gives you array number i. Therefore a pointer to a 1D array can be used to access a 2D array.
A better way to write the malloc call would be this:
p = malloc( sizeof(int[3][3]) );
You example never initializes the arrays, so printing their contents would give garbage and possibly undefined behavior. Corrected code:
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
int(*p)[3];
p = malloc( sizeof(int[3][3]) );
for(size_t i=0; i<3; i++)
{
for(size_t j=0; j<3; j++)
{
p[i][j] = (int)j;
printf("%d ", p[i][j]);
}
printf("\n");
}
free(p);
return 0;
}
Related topic: Correctly allocating multi-dimensional arrays.
malloc is a command to allocate a block of memory according to the size of data you needed (in byte).
in this case you are trying to allocate a block of memory for an array of integer with size of 3.
meanwhile sizeof() is a method to get actual byte size of memory would be used for a data type which is an integer in this case. and because you are needing an array with size of 3, that's why the 3 multiplier comes for
and than you would like to type cast as an pointer into an array of integer with size of 3 to be used later

C multiple files, segmentation fault printing an array

I have this code interaction with 2 files, but I am getting a segmentation error in these two functions and I need help figuring out why. fileA.c passes an int** to a function in fileB.c, the int** serves as an output parameter because I want to make an int array in fileB and have foo point to it so I can print it in fileA. In fileB.c, I make an array, and set the pointer to it.
size and foo are initialized in another function in a main file. It compiles fine, the output though would be (if size == 10) :
0 1 2 3 4 5 6 7 8 9
Segmentation fault
In fileA.c:
void testPointing(int size, int** foo) {
initialize(size, foo);
int i;
for(i = 0; i < size; i++) {
printf("%d ", (*foo)[i]);
}
}
fileB.c:
void initialize(int size, int** foo) {
int* a;
a = (int*)malloc(size * sizeof(int);
int i;
for(int i = 0; i < size; i++) {
printf("%d ", a[i]);
}
printf("\n\n");
foo = &a;
}
I need help fixing and understanding why I am getting a segmentation fault. Whenever I opt to put the loop located in fileA.c after
foo = &a
in fileB.c instead, it compiles and shows a correct output.
The address returned by malloc() is what holds your data, and that's stored in a, not &a. &a is just the address of the local variable a.
Also, foo is just the local function argument of initialize(), not the passed argument of the caller; that's *foo. That leaves the caller's foo unset, which is why you get a segmentation fault.
So instead of:
foo = &a;
you need:
*foo = a;
And the initial call to testPointing() should be something like this:
int* array;
testPointing(size, &array);

Double array through pointers in C

I want to scan a 2D array with the help of pointers and have written this code, could you tell me why the compiler gives errors?
#include<stdio.h>
#include<stdlib.h>
int main(void) {
int i,j,n,a,b;
int (*(*p)[])[];
printf("\n\tEnter the size of the matrix in the form aXb\t\n");
scanf("%dX%d",&a,&b);
p=(int (*(*p)[b])[a])malloc(b*sizeof(int (*p)[a]));
for(i=0;i<b;i++) {
p[i]=(int (*p)[a])malloc(a*sizeof(int));
printf("\t\bEnter Column %d\t\n");
for(j=0;j<a;j++)
scanf("%d",&p[i][j]);
}
return 0;
}
This statement has several problems:
p=(int (*(*p)[b])[a])malloc(b*sizeof(int (*p)[a]));
First, malloc returns a void*. You are casting that pointer using (int (*(*p)[b])[a]) which yields a value, not a data type. That isn't a valid cast, so that's one reason that the compiler is yelling at you. At this point, p hasn't been initialized so the de-referencing taking place here can crash your program if this statement was executed.
Inside your malloc call, you are using sizeof(int (*p)[a]). The statement int (*p)[a] isn't a valid C statement.
It seems that you are making this a bit more complex that it needs to be. There are two ways of building a 2D array. You can build an array using malloc(a * b * sizeof(int)) as Reinderien explains. You can also build a 1D array of pointers, each pointing to an array of type int. From your code, it seems you are trying to do the latter.
The easier way to do this would be something like this:
int **p;
... get input from user ...
// Declare an array of int pointers of length b
p = malloc(b * sizeof(int*));
// For each int* in 'p' ...
for (i = 0; i < b; ++i) {
// ... allocate an int array of length 'a' and store a pointer in 'p[i]' ..
p[i] = malloc(a * sizeof(int));
// ... and fill in that array using data from the user
printf("\t\bEnter Column %d\t\n");
for(j = 0; j < a; j++)
scanf("%d", &p[i][j]);
}
Using this method of building a 2D array allows you to use the syntax p[x][y]. Since p is a pointer-to-pointer, p[x] is a pointer to an array and p[x][y] is an item in the pointed-to array.
That's some pretty contorted syntax. Usually when you make a 2D array:
The declaration is simply int *p;
The allocation is simply p = malloc(a*b*sizeof(int));
You cannot write p[i][j]. You must do one of several things - either make a secondary array int **q that contains row pointers to be able to write q[i][j] (better performance and legibility), or write p[b*i + j] (fewer steps).
Additionally, note that:
Your printf will spew garbage due to the missing %d parameter.
Since C is not typesafe, using scanf will hide any errors in indirection that you may make.
About the closest thing I could think of that remotely resembles what you were trying to do:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i, j;
const int a = 3, b = 4;
int m[4][3];
int (*p[4])[3];
for (i = 0; i < b; i++)
{
p[i] = &m[i];
printf("\t\bEnter Column %d\t\n", i);
for (j = 0; j < a; j++)
{
int x;
scanf("%d", &x);
(*p[i])[j] = x;
}
}
return 0;
}
It compiles and functions as expected, but it's pointlessly complicated. p is an array of pointers to arrays.

Resources