This question already has answers here:
c - passing pointers to a function
(3 answers)
Closed 8 years ago.
I know this is a common problem, however in my case the answer is not that straightforward (or at least I think so).
What I want is to allocate memory for 10 integers (as seen in the scheme below).
Scheme:
_____HEAP_____
| |
**numbers -----> *number ---|--> int |
*number ---|--> int |
*number ---|--> int |
.. | |
*number ---|--> int |
|______________|
Code:
int** numbers;
void malloc_number(int* number){
number = malloc(sizeof(int));
}
int main(){
numbers = malloc(10*sizeof(int*));
int n;
for (n=0; n < 10; n++){
//numbers[n] = malloc(sizeof(int)); // THIS WORKS
malloc_number(numbers[n]); // THIS DOESN'T
free(numbers[n]);
}
free(numbers);
}
I don't seem to understand why this isn't working. In my mind numbers[n] that I pass to malloc_number is a pointer to some unallocated number. Then I use number = malloc(sizeof(int)); (number = numbers[n]) to allocate memory to that pointer.
What am I doing wrong?
void malloc_number(int* number){
number = malloc(sizeof(int));
}
This function leaks memory. Remember C is pass-by-value and number argument is an object with automatic storage duration that got destroyed when malloc_number returns. If you want to modify a pointer through a function you have to pass a pointer to the pointer.
void malloc_number(int* number){
number = malloc(sizeof(int));
}
This code is wrong. You're setting the value of the var "number" which is an argument and is lost after the function call.
The right code would be:
void malloc_number(int** number){
*number = malloc(sizeof(int));
}
...
malloc_number(&numbers[n]);
Please also note that the convention for loop increments to be "i" or "j", n being kind of reserved for the maximum value or limit.
Related
I'm having trouble understanding why the following code gives a garbage value.
EDIT: I need to use malloc, as it's part of the project requirements. I am well aware that it would be easier without using it, but I can't just not use it.
void int_init(int * x) {
x = malloc(sizeof(int));
*x = 7; //could be any number, 7 was chosen for fun
}
int main(void) {
int x;
int_init(&x);
printf("X: %d", x); //Should be "X: 7", is actually "X: 1595803432" or other garbage value
return 0;
}
I'm new to this, so apologies if this question is phrased poorly or is too trivial.
FINAL EDIT: Thanks to Vlad and Avi for helping me out. I may have misread the project description, since it seems like there is no way to use malloc to edit the original value of the variable. In my project, there is a struct that is associated with dynamically allocated memory (it contains an array of dynamically allocated structs), but I thought that it wanted us to dynamically allocate the entire struct. I apologize for the mistake, but am infinitely grateful for everyone's help.
In this function
void int_init(int * x) {
x = malloc(sizeof(int));
*x = 7; //could be any number, 7 was chosen for fun
}
the passed pointer was reassigned with the address of the dynamically allocated memory. So after that the pointer does not pointer to the original variable x declared in main.
As a result this statement
*x = 7; //could be any number, 7 was chosen for fun
assigns a value to the object in the dynamically allocated memory.
Moreover the function produces a memory leak because the allocated memory was not freed.
If you want to change the original variable x declared in main then define the function like
void int_init(int * x) {
*x = 7; //could be any number, 7 was chosen for fun
}
Taking into account your comment to my answer it seems you mean something like the following.
void int_init(int **x) {
*x = malloc(sizeof(int));
**x = 7; //could be any number, 7 was chosen for fun
}
int main(void) {
int *x;
int_init(&x);
printf("X: %d", *x);
free( x );
return 0;
}
I have a question. I wanna pass my own 2D array to pass function.And in that function,i will change my own array.So,there is a return.What i exactly know is that the code blow can be accepted by the compiler.But, i don't why it is.When i take the int (* aaa)[3]; out of the main function,it works well.But , when it is inside the main,there will throw an exception that unable to use the uninitialized aaa.I wonder why could this happan.
int* pass(int (*a)[3]) {
a=(int*)malloc(sizeof(int*)*2);
a[0][1] = 1;
a[0][2] = 2;
return a;
}
int (* aaa)[3];
int main() {
aaa = pass(aaa);
printf("%d", aaa[0][2]);
}
this could work.
int* pass(int (*a)[3]) {
a=(int*)malloc(sizeof(int*)*2);
a[0][1] = 1;
a[0][2] = 2;
return a;
}
int main() {
int (* aaa)[3];
aaa = pass(aaa);
printf("%d", aaa[0][2]);
}
but,this can't work.
When int (* aaa)[3]; appears outside of any function, it aaa is automatically initialized to a null pointer. When it appears inside a function, it is not initialized.
The code aaa = pass(aaa); passes aaa to the routine named pass. This is a use of the value of aaa. When aaa has been initialized, that is fine. But, when aaa is not initialized and you attempt to pass its value, the behavior is not defined by the C standard. This is what the compiler is warning you about.
Next, let’s examine this code:
int* pass(int (*a)[3]) {
a=(int*)malloc(sizeof(int*)*2);
a[0][1] = 1;
a[0][2] = 2;
return a;
}
This code never uses the value of a that is passed to it. When a function is called, its parameter, a in this case, is given a value (which comes from the argument the caller passed). This parameter is a separate variable from the argument. Assigning a a value with a=(int*)malloc(sizeof(int*)*2); does not change the value of aaa in the calling routine. So this code assigns a new value to a without using the old value.
Because of that, the routine does not need a parameter passed to it. It could be written to use a local variable instead, like this:
int (*pass(void))[3] {
int (*a)[3] = malloc(2 * sizeof *a);
a[0][1] = 1;
a[0][2] = 2;
return a;
}
The void in this means pass does not take any arguments.
Note that I changed malloc(sizeof(int*)*2 to malloc(2 * sizeof *a). sizeof(int*)*2 is wrong because it requests space for two pointers to int. But a points to arrays of three int, so, to get two of those, you need space for two arrays of three int. That is 2 * sizeof(int [3]). However, it is easier to write this as malloc(2 * sizeof *a), which means “two of whatever a points to”. This is also better because it reduces the frequency with which errors are made: Even if the declaration of a is changed, this sizeof *a will automatically adjust without needing to be edited. With sizeof(int [3]), any edit to the declaration of a would require another edit to the sizeof.
Also, I removed the (int*) to cast the result of malloc. In C, a void *, which is the type malloc returns, will automatically be converted to whatever object pointer type it is assigned to. There is no need for an explicit cast, and using an explicit cast can mask certain errors. (However, if you compile the program with a C++ compiler, it will complain about the lack of a cast, because the rules are different in C++.)
Since the function is returning a pointer to an array of three int, not an pointer to an int, I changed its declaration to int (*pass(void))[3].
With these changes, the program could be:
#include <stdio.h>
#include <stdlib.h>
int (*pass(void))[3]
{
int (*a)[3] = malloc(2 * sizeof *a);
a[0][1] = 1;
a[0][2] = 2;
return a;
}
int main(void)
{
int (*aaa)[3] = pass();
printf("%d\n", aaa[0][2]);
}
maybe this helps you a bit to see that C is 'flexible' when it comes to arrays.Because in the first part the assumed array declaration is given by datalen in malloc of the initAAA function and returns the pointer to the memory that is allocated. And still in the for loop we can access the data with index.
The second part of main declares just same data 'bbb' as the first 'aaa' but this time not as pointer and the initiation of the data fields with zeros (0) is done with the curly parenthesis. {}. A boring for loop thru all the indexes and set each data field with int 0 would just do it also. But who wants more code than needed.
#include <stdio.h>
#include <string.h>
int *initAAA(int *p, uint entrys) {
size_t datalen = entrys * sizeof *p;
p = malloc(datalen); // p is a pointer here.
// copy character '0' starting at address of p up to datalen addresses
// easier then writing a for loop to initiate safely.
memset(p, 0, datalen); // defined in string.h
return p;
}
int main(void) {
const uint maxAssets = 3;
const uint entrysPerAsset = 2;
int *aaa = NULL; // always a good idea, to set pointers to NULL before allocating memory for it. Because you can check if (aaa==NULL) initAAA(...
uint entrys = maxAssets * entrysPerAsset;
aaa = initAAA(aaa,entrys);
printf("address:%p items:%d \n",aaa, entrys);
for (uint i = 0; i < entrys; i++) {
printf("%d ", aaa[i]);
}
free(aaa); // malloc without free, bad idea!
printf("\n---\n");
int bbb[maxAssets][entrysPerAsset] = {0,0,0,0,0,0};
for (uint a = 0; a < maxAssets; a++) {
for (uint e = 0; e < entrysPerAsset; e++) {
printf("%d ", bbb[a][e]);
}
}
// bbb does not need free(bbb); because it is released with the function end.
// and yep, there was no malloc for bbb. so we are done.
}
and by the way. welcome to C.
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.
I wrote a simple code to create an array of pointers to integer and then fill it with scanf while I was using k&R book to do such things this time I tried to use malloc function but encountered a weird problem
here is the code:
#include<stdio.h>
#include<stdlib.h>
#pragma warning(disable:4996)
int getArr(int **myArr);
void print(int *myArr, int n);
int main() {
int *myArr, n;
n = getArr(&myArr);
print(myArr, n);
return 0;
}
int getArr(int **myArr) {
int n;
scanf("%d", &n);
*myArr = (int *)malloc(n * sizeof(int));
for (int i = 0; i < n; i++)
scanf("%d", myArr+i); /* here if i put &(*myArr)[i] will work correctly */
return n;
}
void print(int *myArr, int n) {
while (n-- != 0) {
printf("%d\t", *myArr);
myArr += 1;
}
return;
}
but what is the difference between this two types of reading input?
The %d format specifier to scanf expects a int *.
The expression myArr+i has type int ** which doesn't match what is expected, while &(*myArr)[i] (or alternately *myArr+i) has the correct type int *.
since you need the value of the pointer to be updated out of the procedure you rightfully did:
*myArr = (int *)malloc(n * sizeof(int));
(except that you shouldn't cast the return value of malloc in C)
But after that *myArr is the pointer to scan from. myArr is a pointer on the pointer. So you need to keep dereferencing myArr
scanf("%d", (*myArr)+i);
The problem is in getArr() function as myArr is double pointer & while scanning data you should use (*myArr) + i) instead of just myArr + i. Also myArr is not initialized in main() function.
Here is the modified one
int getArr(int **myArr) {
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
myArr[i] = malloc(sizeof(int));/*allocate memroy here */
scanf("%d", (*myArr) + i);
}
return n;
}
Your code:
int getArr(int **myArr) {
int n;
scanf("%d", &n);
*myArr = (int *)malloc(n * sizeof(int));
for (int i = 0; i < n; i++)
scanf("%d", myArr+i); /* here if i put &(*myArr)[i] will work correctly */
return n;
}
Your memory layout looks something like this:
myArr (a pointer who lives on the stack in main()
|
| (points to)
V
[XXXX XXXX XXXX XXXX] (allocated by malloc)
The 4 X's together represent an integer, so this is an array of some sequence of them. When you dereference myArr, you get the pointer to the beginning of the array. When you index THAT pointer, you get elements in the array.
Your code is not doing that:
myArr+i
This is treating myArr as a pointer to array, not a pointer to a pointer. When you provide myArr + i, you're effectively doing this:
myArr --------------------> [WRITE HERE]
|
|
V
[XXXX XXXX XXXX XXXX]
(Imagine memory goes left to right, row by row, so that the array is "far" from myArr, and [WRITE HERE] is closer to it. By adding to the myArr pointer, you're moving into invalid memory areas. myArr literally holds an address in main (since that's where you originally declared it, and passed its address to this function.) When you add to it, you are computing an address somewhere in the main stack frame, and scanf treats it as a pointer to an int, and scribbles some bytes somewhere into your stack.
Your alternate syntax is doing something different:
&(*myArr)[i]
This dereferences myArr, fetching the beginning of your malloc'd array, then indexes into the array for the i'th offset int, then takes the address of that int and passes it to scanf.
The reason this works this way is that [] has higher precedence than &, and so it's equivalent to this:
&((*myArr)[i])
This is the correct way to access your memory given this scheme.
It is good to learn this, but the days of K&R C-style coding are fading, especially in c++ code bases, as the danger and error-prone nature of working with raw pointers like this (as you've discovered) have fortunately been superseded by c++ idioms to help encapsulate memory access and reduce hard to comprehend bugs.
This question already has answers here:
Why isn't the size of an array parameter the same as within main?
(13 answers)
Array length counting anomaly
(4 answers)
Closed 8 years ago.
I use a macro to get the number of the elements of an integer array, and I could get the right result of the number of the integer array in the main function, but I got the wrong answer if I use a getData function and send the pointer of the integer array as a parameter. I want to know why I got this wrong answer. Thank you!
the code of my program as follow:
#include <stdio.h>
#define LENGTHOFINTARRAY(intArray) ((int)(sizeof(intArray)/sizeof(int)))
int main (int argc, char *argv[])
{
int a[] = {5,8,9,4,11,7,15,25,1};
int getData(int *data);
printf("%d\n", LENGTHOFINTARRAY(a));
getData(a);
return 0;
}
int getData(int *data)
{
int i = 0;
for(i; i < LENGTHOFINTARRAY(data); i++)
{
printf("%d, %d\n", LENGTHOFINTARRAY(data), data[i]);
}
return 1;
}
and the result of my program is:
9
1, 5
I use gcc as my compiler.
The type of int* data is just int* and not int[9] like in main. The size of int* is is the size of any other pointer (4 or 8 bytes usually). There is no way to get the size of an array from the pointer.
And since arrays can't be passed by value in C (unless inside a struct or something) you have to pass the length of the array.
getData() sees data as an int*. It does not know how long it is.
You cannot determine the size of an array that is passed as a pointer to a function.
As you have defined
int a[] = {5,8,9,4,11,7,15,25,1};
int getData(int *data);
printf("%d\n", LENGTHOFINTARRAY(a));
getData(a);
so when you call "getData(a)" then it means you are passing the address of the very first element as &a[0];
so inside you function getData() as
int getData(int *data)
{
int i = 0;
for(i; i < LENGTHOFINTARRAY(data); i++)
{
printf("%d, %d\n", LENGTHOFINTARRAY(data), data[i]);
}
return 1;
}
the data is just a pointer to integer & it gets the pointer or address of the a[0];
so your macro now sees data as pointer to int. which causes the result as u have gotten.