C pointer frustration EXC_BAD_ACCESS - c

Can someone please tell me what's wrong with the following code? I'm getting EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS
I declare a global array of 7 pointers, each points to an int array, of different sizes.
int **pt_all_arrays[7];
In my function A()
for (int i = 0; i < 7; ++i) {
int array_size = function_that_returns_array_size();
int *myarray = (int *)malloc(array_size * sizeof (int));
// DO WORK...
// Store the array in the big array
*(pt_all_arrays[i]) = myarray; <-----EXCEPTION
}
The exception is thrown on the last line.
I'm running on Mac, gcc -std=gnu99

You would want to declare as
int *pt_all_arrays[7];
And then assign as
pt_all_arrays[i] = myarray;
With int **pt_all_arrays[7]; you create array of pointer to pointer to int, which is not what you want.
And with *(pt_all_arrays[i]) = myarray; you are trying to change to address of array which is not valid.
Example
int array[7];
int *pi;
array = pi; //this is not valid.

the definition of
int **pt_all_arrays[7];
should be
int *pt_all_arrays[7];

In the last line , you try to write to the memory location pointed by pt_all_arrays[i]. Since pt_all_arrays[i] hasn't been initialized, this might point anywhere. In your case, it points to an invalid memory address.

int **pt_all_arrays[7];
This actaully declaires an array of 7 pointers to pointers to ints. (pointers to int arrays). So if you want to store arrays you just need:
int *pt_all_arrays[7];
When you access the array:
pt_all_arrays[i]
This is actually saying the same as:
*(pt_all_arrays + i)
So you don't want to add the additional * in to it, simply:
pt_all_arrays[i] = myarray;
Will do.

Related

Passing array by ref causes compiler warnings - How to use pointer-arithmetic correct here?

void foo(int **arr)
{
**arr = 5; // works fine, no warnings and myArray[0] is 5 after call.
*(arr+5) = 5; //warning - assignment makes pointer from integer without a cast - why?
*(arr)[5] = 5; //No warnig but programm would crash
}
int main()
{
int *myArray = (int*)calloc(10,sizeof(int));
foo(&myArray); //no warning but myArray[5] would be still 0
foo(myArray); //warning - passing argument 1 of 'foo' from incompatible pointer type (but works fine)
printf("%d",myArray[5]);
return 0;
}
How to pass the array correctly to my function and access myArray[5] without any warnings?
As written, the proper way to index into arr would be
(*arr)[5] = 5;
Since arr is a pointer to a pointer to your array, you don’t want to index into arr, you want to index into what arr points to. You need to explicitly group the * with arr since postfix operators like [] have higher precedence than unary *.
Having said that, the only reason to pass a pointer to myArray is if you expect to change the value of myArray itself, such as with a call to realloc. If that’s not the intent, then it’s better to write the function as Antti and Peter have shown.
Since foo takes a pointer to a pointer to integer, calling foo(&myArray) is correct here. But you don't need to do that at all. Simply pass in myArray and have foo take a pointer to int instead:
void foo(int *arr)
{
arr[5] = 5;
}
int main()
{
int *myArray = calloc(10, sizeof(int)); // no need to cast here unless compiling with a C++ compiler
foo(myArray);
printf("%d", myArray[5]); // prints 5
return 0;
}
I know pointers can be confusing, but there seems to be a very fundamental misunderstanding here so I recommend carefully reading the pointer section of any good C textbook again.
Like this:
#include <stdio.h>
#include <stdlib.h>
void foo(int *arr) {
arr[5] = 5;
}
int main(void) {
int *myArray = calloc(10, sizeof(int));
foo(myArray);
printf("%d", myArray[5]);
}
You only need to pass the pointer by reference if you want to change the value of the original pointer object (i.e. if you want to make the pointer stored in myArray point to another allocated memory block after calling foo).

Reason for Segmentation fault vs returning random values with the following C code

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.

C language Array modification with Malloc

void helperWithoutMalloc(int *arr) {
arr[0] = 18;
arr[1] = 21;
arr[2] = 23;
}
int main() {
int *data;
helperWithoutMalloc(data);
printf("%d\n", data[0]);
return 0;
}
The above method successfully modify the value of data through the method helperWithoutMalloc(); however, when malloc method is applied; similar way doesn't work. Three value in the data array still zero
void helperNotWorking(int *arr) {
arr = malloc(sizeof(int)*3);
arr[0] = 18;
arr[1] = 21;
arr[2] = 23;
}
int main() {
int *data;
helperNotWorking(data);
printf("%d\n", data[0]);
return 0;
}
I'm just wondering what happen when the line arr = malloc(sizeof(int)*3) is implemented; and makes two code so different?
The main confusion is that : first code regardless of its incorrectness, can still modify the array element while second code, can't modify the array elements; since both functions pass the address of array; and we manipulate the array element through address
Any data structure in C as in any other language must be provided with a memory region where it data could be kept. In your first example you failed to do so. The 'data' pointer does not point to any memory and is initialized. It worked by a chance and you just caused your program to write data somewhere, which happened to be writable. you needed something like the following:
int main() {
int data[3]; // allocate an array for data
helperWithoutMalloc(data);
In the above example the memory was provided by the C array of 3 elements.
In a similar fashion you can use malloc:
int main() {
int *data = malloc(sizeof(int) * 3);
helperWithoutMalloc(data);
Note that the space for data was allocated before calling to the function and passed to it. The function can use pointer (memory address) to access the array elements.
In your second example you did a different mistake. You allocated the space, but you assigned the pointer to the parameter of the function. The pointer in your case was passed to your function by value, therefore it is uni-directional. you can pass it to the function but not backwards. It worked perfectly well inside the function but it did not update 'data', so you cannot access the values after returning from the function. There are few ways to work around it. I.e. you can return your pointer from the function:
int *helper() {
int *arr = malloc(sizeof(int)*3);
...
return arr;
}
int main() {
int *data = helper();
...
or you can use a pointer to pointer to pass to the function:
void helper(int **arr) {
*arr = malloc(...)
(*arr)[0] = 0;
...
}
int main () {
int *data;
helper(&data);
In my opinion, the correct way should be
void NoMalloc(int *arr) {
arr[0] = 18;
arr[1] = 21;
arr[2] = 23;
}
int main() {
int *data = (int *)malloc(sizeof(int) * 3);;
NoMalloc(data);
printf("%d\n", data[0]);
free(data);
return 0;
}
The malloc function allocates some memory and returns a pointer to that allocated memory.
Pointer stores addresses in the memory, and when you define a uninitialized pointer (such as the your first piece of code, int * data;) you don't know where the pointer (data) is pointing and therefore accessing the values stored at the location would often cause Access Violations and should never be used.
As with any other type of C variables, pointers are passed by values when serving as an argument of a function. So data itself would not be modified after calling helperWithoutMalloc or helperNotWorking. The second piece of code does not work because after calling helperNotWorking, the data pointer is still an uninitialized pointer. The numbers you though you have stored in data is actually stored in the modified value of arr in the helperNotWorking function, which does not affect does not point to the same address as data anymore.

Expression must be a modifiable lvalue when mallocing

I understand this question has been asked before, but I can't quite narrow down what i've done wrong here
int* arr[2];
arr = (int (*)[2]) malloc(sizeof(int) * size);
why is visual studio telling me the expression must be a modifiable lvalue? I'm trying to create an array with a constant column size, since that will always be two, but the rows will vary.
arr is an array of pointers. You cannot assign anything to it once it is initialized. Since you are trying to set its value to be the return value of a call to malloc, you probably want it be a pointer to an array. In that case, use:
int (*arr)[2];
Also, don't cast the return value of malloc. See Do I cast the result of malloc?.
Use
int (*arr)[2];
arr = malloc(sizeof(*arr) * size);
// ^^^^^^^^^^^^ We are speculating this is what you need,
// not sizeof(int)
If you want arr to point to an array of 15 x 2 objects, you will need to use:
arr = malloc(sizeof(*arr) * 15);
you have an array of pointers.... that array can't be used as a pointer itself, only the array entries are pointers.
you need a pointer to pointers, int **, unless you are wanting an array of ints, then you just int* arr
Did you consider using a struct? Then the syntax is a little more straight forward.
#include <stdlib.h>
typedef struct Two Two;
struct Two{
int b[2];
};
int main(){
int size = 100;
Two* two = malloc(sizeof(Two)*size);
return 0;
}

What does (*ptr)[10] mean?

void main()
{
int (*d)[10];
d[0] = 7;
d[1]=10;
printf("%d\n",*d);
}
It should print 10 but compiler is showing error such as follows:
test.c:4:7: error: incompatible types when assigning to type ‘int[10]’ from type ‘int’
Note that I have included some errors , not all.
As noted by chris, d is a pointer to an array. This means you use the variable improperly when you access it, but also that you will access random memory unless you assign d to point to a valid array.
Change your program as follows:
int main(void)
{
int (*d)[10]; /* A pointer to an array */
int a[10]; /* The actual array */
d = &a; /* Make `d` point to `a` */
/* Use the pointer dereference operator (unary prefix `*`)
to access the actual array `d` points to */
(*d)[0] = 7;
(*d)[1] = 10;
/* Double dereference is okay to access the first element of the
arrat `d` points to */
printf("%d\n", **d);
return 0;
}
In C, [] is the same as *, the pointer syntax. Thus the following lines are the same:
int** array2d1;
int* array2d2[];
int array2d3[][];
To relate to a closer example, the main function has the following popular forms:
int main(int argc, char** argv){ ... }
or
int main(int argc, char* argv[]){ ... }
Thus
int (*d)[10]
is the same as
int* d[10]
which is the same as
int** d;
int firstArray[10];
d = &firstArray;
Effectively, you are creating a pointer to a pointer (which is a pointer to an array) and allocating the first pointer to an array that 10 elements. Therefore, when you run the following lines:
d[0] = 7;
d[1] = 10;
You are assigning the 1st array's address to 7 and the second array's address to 10. So as Joachim has mentioned, to assign values, you need to deference twice:
(*d)[0] = 7
(*d)[1] = 10
Which says "Assign 7 to the 0th index at the value pointed by d". I hope that makes sense?
d is a pointer to an array of 10 ints.
int (*d)[10] is the declaration for a point to an array of 10 ints.
vs.
int *d[10], which is an array of 10 int pointers.
For more complex syntax like this (usually involving pointers), I use cdecl to help me decode it.
It's used in this form
int d[10]
I guess you are mistaken that d must be a "kind of pointer" and therfor you put an * before the d.
But that's not what you want. You wan to name an array of integer and the notation for that is seen above.
Concept of pointer can get confusing sometimes in C.
Consider an array int d[6] = {0,1,2,3,4,5}
Then, *d is equivalent to d[0]. d is itself an pointer to an array and *d dereferences that pointer and gives us the value.
Hence, following code would print the same values:
int main()
{
int (d)[10];
*d = 7;
*(d + 1)=10;
printf("%d\n",*d);
printf("%d\n",d[0]);
return 0;
}
result:
7
7
Please see http://codepad.org/LYY9ig1i.
If you change your code as follows:
#include<malloc.h>
int main()
{
int *d[10]; //not (*d)[10]
d[0] = (int *)malloc(sizeof(int *) * 10);
d[0][0] = 7;
printf("%d\n",d[0][0]);
return 0;
}
Hope this helps you!

Resources