How to pass the 2D array point to the other functions? - arrays

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.

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

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.

Structures and linked list accessing.

#include <stdio.h>
int main(void)
{
typedef struct{
int a;
} cool;
cool x;
(&x)->a = 3;
x.a = 4;
}
I was wondering if the (&x)-> a does the same thing as the x.a. I coded both of them up, and it seemed that both of them changed the value of x.a. I know it must be a pointer on the left side of ->, but the (&x) seems to work without problem. Printing out x.a works for both of them, and gives me the correct answer. I looked up a lot about pointers, linked list, and structures and am still not able to find out the answer. Would it be possible to get an explanation? Thank you!
The -> operator expects a pointer on the left hand side. &x returns the address of x so it satisfies that requirement (even if it is totally redundant). To think about it another way...
cool *y = x;
y->a = 3;
The . operator expects a stack allocated struct on the left hand side. x is that, so x.a works fine.
You can also go the other way, if you have a pointer y you can dereference it with *y and use . on it: (*y).a. This is also totally redundant.
The & prefix operator returns the memory address of whatever object you put it in front of.
This means that you have to put it in front of objects that actually have a memory address. For example, literals and temporary expression results don't necessarily have an address. Variables declared with register storage class don't have an address, either.
Thus:
int i = 5;
&i; // works
&5; // Nope!
&(i + 1); // Nope!
&i + 1; // Works, because &i has higher precedence than +1.
So what does the address of an object give you? It is a pointer to the object. This is how you can do dynamic memory allocation using the heap. This is where functions like malloc() come in. And this is how you can build arbitrarily large data structures.
In C, arrays are represented as pointers. So arrays and pointers are often used interchangeably. For example:
char buffer[100]; // array
strcpy(buffer, "hello"); // strcpy is declared to take (char *, const char *)
The opposite of the address_of operator is the * dereference operator. If I declare a pointer to something, I can get "what it points at" using this syntax:
int i = 5;
int *pi = &i; // pointer to int. Note the * in the declaration?
i + i; // 10
i + *pi; // Also 10, because pi "points to" i
In the case where you have an aggregate type like a struct or union, you would have to do something like this:
struct {
int a;
} s;
s.a = 5;
/* ??? */ ps = &s; // pointer to s
s.a; // 5
(*ps).a; // Also 5, because ps points to s.
ps->a; // 5, because a->b is shorthand for (*a).b
This only works, of course, if you have a pointer to an object that CAN use the .member and that has an appropriately named member. For example, you can't do this:
i = 5;
pi = &i;
pi->a; // WTF? There is no i.a so this cannot work.
If you have a pointer, you can take the address of it. You then have a pointer to a pointer. Sometimes this is an array of pointers, as with the argv array passed to main:
int main(int argc, const char *argv[]);
int main(int argc, const char **argv); // Effectively the same.
You can do weird stuff with pointers to pointers:
int i = 5;
int j = 100;
int * pij;
for (pij = &i; i < j; ) {
if (i & 1) {
*pij *= 2;
pij = &j;
}
else {
i += 1;
*pij -= 1;
pij = &i;
}
}
Note: I have no idea what that code does. But it's the kind of thing you can wind up doing if you're working with pointers.

assign dynamic array in a function and send it back to the caller in C

I have been using java for long time but for some reason I need to use C (ANSI C not C++) to write a simple code. I need to pass the pointer from outside to a function, allocate some memory to the pointer and assign some values also before the function return. I have my code like
#include <stdio.h>
#include <stdlib.h>
void test(int *a)
{
int n=3;
// I have to call another function t determine the size of the array
n = estimatesize(); // n >=3
// I tried fix size n=10 also
a = (int*)malloc(n*sizeof(int));
a[0] = 1;
a[1] = 2;
a[2] = 3;
}
void main(void)
{
int *s=NULL;
test(s);
printf("%d %d %d", s[0], s[1], s[2]);
}
I don't know why the code crashes. I thought at the beginning it is estimatesize() return wrong number but even I fix n to 10, the error still there. So I cannot pass a pointer to a function for memory allocation? If so, how can I dynamically create memory inside a function and pass it out? I know it may be a safe problem in this way but I just want to know if it is possible and how to do that. Thanks.
There are two solutions to this: Either return the pointer from the function, or pass the argument by reference.
For the first one, you simply don't take any arguments, instead you return the pointer:
int *test(void)
{
int *a = malloc(...);
...
return a;
}
int main(void)
{
int *s = test();
...
}
For the second one, you need to pass the address of the pointer, in other words a pointer to the pointer, using the address-of operator &:
void test(int **a)
{
*a = malloc(sizeof(int) * 3);
for (int i = 0; i < 3; ++i)
(*a)[i] = i;
}
int main(void)
{
int *s;
test(&s);
...
}
The reason it doesn't work now, is because the pointer (s in main) is passed by copying it. So the function test have a local copy, whose scope is only in the test function. Any changes to a in the test function will be lost once the function returns. And as s is copied for the argument, that means that s in main never actually changes value, it's still NULL after the function call.

c language. Return type of a function

?? fun()
{
int a[3]={3,3,4};
return &a;
}
what could be the compatible return type. Here the pointer is pointing to the array of 3 integers not just the pointer which points to integer array.
Aim is to return a pointer to array of 3 integers.
First, you really should not return the address of a local variable. When the function exits, the array a will get destroyed.
As for your question, the type of &a is int (*)[].
Don't do this.
You are returning a pointer to a local variable. When the function returns, that pointer points to a location that's no longer valid, so this exercise is pointless.
The return type would have been int (*)[3] though, but when you use that as a return type of a function, the prototype would be int (*fun(void))[3] (ugh, eew)
However
If a was static, you could do
int (*fun(void))[3]
{
static int a[3]={3,3,4};
return &a;
}
It's more common to return a pointer to the first element in an array - though you'll have to "know" in the caller that you can access 3 and only 3 elements of that pointer.
int *fun(void)
{
static int a[3]={3,3,4};
return &a[0]; // or just return a;
}
Since a is static in these cases, you'll have to worry about reentrancy
2 more common ways of achieving the same:
Pass in the array through the parameters and allocate it in the caller:
void fun(int *a)
{
a[0] = 3;
a[1] = 3;
a[2] = 4;
}
Call it like:
int a[3];
fun(a);
Dynamically allocate the memory:
int *fun(void)
{
int *a = malloc(3*sizeof *a);
if(a) {
a[0] = 3;
a[1] = 3;
a[2] = 4;
}
return a;
}
Call it like:
int *a;
a = fun();
if(a) {
///use a
free(a); // remember to free it when done
} else {
//out of memory
}
The return type would not be an int* or int** as others have suggested. The return type would be a pointer to an array. For example:
// we'll use a typedef so we can keep our sanity:
typedef int(*int3arrayptr)[3];
int3arrayptr fun()
{
int a[3]={3,3,4};
return &a;
}
While you can return a pointer to a local variable, you cannot use such a pointer after the function returns, so you cannot use the return value of fun().
The type would be int**
But your code is wrong because your table is on the stack.
Returning the pointer of an element in the stack make the reference pointing in nowhere when returning from the function.
Don't make the mistake. As soon as fun() loses scope, so does all it's local variables.
The address of a local variable cannot be returned from a function. Local variables are placed in the stack
a is a local variable. Don't return a pointer to it.
Back to the point. This is how you define a pointer-to-array-of-size-3 type in C:
int a[3] = { 1, 2, 3 };
typedef int (*p_arr_3)[3];
p_arr_3 fun() { return &a; }
Everyone else has already told you why you shouldn't do this as it is written, but here are the types you are interested in.
Given a declaration int a[3], the type of the expression &a is int (*)[3] (not int **), or "pointer to 3-element array of int", such as
void f()
{
int a[3] = {1,2,3};
int (*aptr)[3] = &a;
...
}
and the signature for a function returning that type would be int (*fun())[3] {...}.
One other option nos didn't show is this:
int (*fun())[3]
{
int (*aptr)[3] = malloc(sizeof *aptr);
if (aptr)
{
(*aptr)[0] = 1; // array pointer must be deferenced before applying
(*aptr)[1] = 2; // the subscript.
(*aptr)[2] = 3;
}
return aptr;
}
although this isn't terribly useful; you don't normally see allocations of single, fixed-size arrays like this. Somewhat more useful is allocating an array of those arrays:
int (*fun(size_t count))[3]
{
int (*aptr)[3] = malloc(sizeof *aptr * count);
if (aptr)
{
size_t i;
for (i = 0; i < count; i++)
{
aptr[i][0] = 1; // aptr[i] implicitly dereferences aptr, so
aptr[i][1] = 2; // there's no need for an explicit dereference
aptr[i][2] = 3; // here.
}
}
return aptr;
}
Even so, if somebody needs to allocate a fixed-size array type, they usually hide it behind a typedef:
typedef int fixedSizeRecord[SOME_SIZE];
...
fixedSizeRecord *fun(size_t count)
{
fixedSizeRecord *aptr = malloc(sizeof *aptr * count);
if (aptr)
{
// initialize contents as necessary
for (size_t i = 0; i < count; i++)
for (j = 0; j < sizeof *aptr / sizeof *aptr[0]; j++)
aptr[i][j] = ...;
}
return aptr;
}
Abstraction is a good thing.
I've put up several iterations of this table before; you might find it handy.
Declaration: T a[N];
Expression Type Decays To Value
---------- ---- --------- -----
a T [N] T * Address of first element in a
&a T (*)[N] n/a Address of a (same value as above,
but different type)
*a T n/a Same as a[0]
a[i] T n/a Value at index i
&a[i] T * n/a Address of value at index i
sizeof a size_t Total number of bytes in a
(N * sizeof T)
sizeof a /
sizeof *a size_t n/a Number of elements in a (N)
Declaration: T a[N][M];
Expression Type Decays To Value
---------- ---- --------- -----
a T [N][M] T (*)[M] Address of first element in a[0]
&a T (*)[N][M] n/a Address of a (same value as above,
but different type)
*a T [M] T * Same as a[0]
a[i] T [M] T * Address of first element in array
at index i
&a[i] T (*)[M] n/a Address of array at index i (same
value as above, but different
type)
*a[i] T n/a Same as a[i][0]
a[i][j] T n/a Value at a[i][j]
&a[i][j] T * n/a Address of value at index i,j
sizeof a size_t n/a Total number of bytes in a
(N * M * sizeof T)
sizeof a /
sizeof *a size_t n/a Number of subarrays in a (N)
sizeof a[i] size_t n/a Total number of bytes in a[i]
(M * sizeof T)
sizeof a[i] /
sizeof *a[i] size_t n/a Number of elements in a[i] (M)
If you want to return a pointer to an array, don't return the address of local variables. What you are returning here would be int**. What you want to do is allocate a new array of int, and return int*. What you want is probably something like:
int* fun()
{
int* a = malloc(sizeof(int) * 3);
a[0] = 3;
a[1] = 3;
a[2] = 4;
return a;
}
You then need to make sure to free the allocated array later.
Your function would have a return type of int * and you would call it like this:
int *array=fun();
printf("%d\n",array[0]); //print the first value in the array
Although! Keep in mind that this function is returning a reference to a locally created variable. There is no guarantee that the value in memory will be the same between inside and after the function call. You probably want to do something more like this:
int *more_fun(){
int *a=malloc(sizeof(int)*3);
a[0]=3;
a[1]=3;
a[2]=4;
return a;
}
Call it like:
int *array=more_fun();
printf("%d\n",array[0]); //print the first value in the array
But when you're done, make sure to free(array) so you don't leak any memory.
If you were to return a, the return type would be int *. I'm not entirely sure what &a means in this case, and my handy reference tells me that the only operation that can be applied to an array is sizeof, and I don't have the Standard handy. It may be flagged as illegal, or it may just return the value of a. The only thing a denotes is the array, and the only thing like a pointer to an array is a pointer to its first element. There is no address of the address.
In C, it's hard to pass around an array, since arrays decay to pointers on the slightest provocation. If you need to pass around an actual array, it's easiest to embed it in a struct. A struct containing int a[3]; can be passed around as a regular value.
I assume that you were just giving an example, because you're returning a reference to a local variable leads to all sorts of bad things. In most implementations, that memory will be used for other things with the next function call, which means that changing a value will stomp on who-knows-what, and referencing one will get who-knows-what.

Resources