I have the following c source. But I get a warning as mentioned below
void check_func();
int var2[16][128];
int var1[][128];
int i, k;
int main()
{
for (i = 0u; i < 16; i++)
{
for (k = 0u; k < 128; k++)
{
var2[i][k] = 4095;
}
}
check_func();
//printf("%d", var1[0]);
return 1;
}
void check_func()
{
var1 = &var2[0][0];
return;
}
I get a warning when compiled in gcc.
E:\gcc-2.95.2\bin>gcc.exe check.c
check.c: In function check_func':
check.c:24:var1' has an incomplete type
check.c: At top level:
check.c:3: warning: array `var1' assumed to have one element
What is the reason for this warning and how to get rid of this?
I tried type casting it to both (int (*)[]) and (void *) but still the warning persits.
i.e.
1st try:
var1 = (int (*)[])&var2[0][0];
2nd try:
var1 = (void *)&var2[0][0];
First, let's ignore the 2D array aspect. It's not quite relevant to a fundamental misunderstanding that you have about arrays and pointers, and it adds extra complication.
With var1, you're basically attempting to declare a global variable:
int x[];
which isn't legal. Based on your comments, you seem to be under the mistaken impression that this declares a pointer, but it instead declares an array of unspecified size. As a global variable, the compiler must be able to allocate memory for this array, but that isn't possible without knowing its size.
Note that this would be different if such a declaration were used for a function parameter:
void foo(int x[]);
When used as function parameters, int x[] and int* x are interchangeable. The function does not allocate any space for the array; the array must have been allocated already, and the function instead takes a pointer to that array (or more precisely, to the array's first element).
Pointers and arrays are not the same thing. Arrays decay into pointers in certain contexts, and function parameters allow using either syntax, but they are otherwise distinct.
Based on what you're trying to do in check_func:
var1 = &var2[0][0];
you probably want to declare var1 simply as:
int* var1;
var2 is a 2D array of int.
Therefore var2[0][0] is of type int.
Therefore &var2[0][0] is of type int*.
Therefore var1 should be of type int* to match.
Related
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).
In C, because of the framework I use and generate though a compiler, I am required to use global variable length array.
However, I can not know the size of its dimension until runtime (though argv for example).
For this reason, I would like to declare a global variable length array with unknown size and then define its size.
I have done it like that :
int (*a)[]; //global variable length array
int main(){
//defining it's size
a = (int(*)[2]) malloc(sizeof(int)*2*2);
for(int i=0;i<2; i++){
for(int j=0;j<2; j++){
a[i][j] = i*2 + j;
}
}
return 0;
}
However, this does not work : I get the invalid use of array with unspecified bounds error. I suspect it is because even if its size is defined, its original type does not define the size of the larger stride.
Does someone know how to solve this issue ? Using C99 (no C++) and it should be quite standard (working on gcc and icc at least).
EDIT: I may have forget something that matters. I am required to propose an array that is usable through the "static array interface", I mean by that the multiple square bracket (one per dimension).
First a is not an array but a pointer to an array of unspecified length. What you are trying to do is not possible. You can't have a global variable length array.
But with the present scenario you can use this to access the memory allocated to a
for(int i=0;i<2; i++){
int *ptr = *a + 2*i;
for(int j=0;j<2; j++){
ptr[j] = i*2 + j;
}
}
You cannot declare a global multi dimensional VLA, because even if you use pointers, all the dimensions except for the first one must be known at declaration time.
My best attempt would be to use a global void *. In C void * is a special pointer type that can be used to store a pointer to any type, and is often used for opaque pointers.
Here you could do:
void *a; // opaque (global variable length array) pointer
int main() {
//defining it's size
a = malloc(sizeof(int) * 2 * 2); // the global opaque pointer
int(*a22)[2] = a; // a local pointer to correct type
for (int i = 0; i<2; i++) {
for (int j = 0; j<2; j++) {
a22[i][j] = i * 2 + j;
}
}
return 0;
}
When you need to access the global VLA, you assign the value of the opaque global to a local VLA pointer, and can then use it normally. You will probably have to store the dimensions in global variables too...
So I am working on an assignment and I am having trouble figuring out how to use this 2d array which was passed by reference.
What I am given is this
int main(){
//cap and flow initialized
maximum_flow(1000, &(cap[0][0]), &(flow[0][0]));
}
So I wanted to copy the contents of cap over to another 2d array I dynamically allocated, but after hitting an error I decided to print out the values I have in cap2 and capacity, I'm not getting back all the values that I should.
void maximum_flow(int n, int *capacity, int *flow){
int **cap2;
cap2 = (int**) malloc(sizeof(int *)*n);
for (i = 0; i < n; i++)
{
cap2[i] = (int*) malloc(sizeof(int)*n);
}
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
cap2[i][j] = (*(capacity + i*n + j));
(*(flow + i*n + j)) = 0;
}
}
}
This isn't going to be a terribly useful answer, since your code doesn't actually show the problem described; based on what's presented, I see no obvious reason why cap and cap2 shouldn't have the same contents by the end of the maximum_flow function. But I'd like to offer some background and a suggestion.
I'm going to assume cap and flow are declared as n by n arrays of int in main, where n is known at compile time.
The reason your instructor is using this interface is that passing multidimensional arrays as function arguments is problematic in C. Remember that unless it's the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaraiton, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array.
So, assuming a declaration like
int cap[10][10];
int flow[10][10];
the expressions cap and flow will each "decay" to type int (*)[10] (pointer to 10-element array of int). So if you wrote your function call as
maximum_flow( 1000, cap, flow );
then the function definition would have to be written as
void maximum_flow( int n, int (*cap)[10], int (*flow)[10] ) { ... }
or
void maximum_flow( int n, int cap[][10], int flow[][10] ) { ... }
In the context of a function parameter declaration, T a[][N] and T (*a)[N] mean the same thing.
The size of the outer dimension has to be specified in the array pointer declaration, and the problem is that a pointer to a 10-element array is a different, incompatible type from a pointer to an any-value-other-than-10-element array; thus, maximum_flow could only ever be used for N x 10-element arrays, limiting its usefulness. One way around this problem is to have the function receive an explicit pointer to the first element, and treat that pointer as a 1D array of size N * M.
Long story short, since you're treating your input parameters as 1D arrays, you are probably better off creating cap2 as a 1D array as well:
int *cap2 = malloc( sizeof *cap2 * n * n );
...
cap2[i * n + j] = capacity[i * n + j]; // use array subscript notation instead
flow[i * n + j] = 0; // of explicit dereferences
From the code you've posted, it's not clear what maximum_flow is supposed to do, nor why you need cap2. Note also that at some point you need to free the memory allocated to cap2, otherwise you have a memory leak.
If you're using a C99 or later compiler, you should be able to use a variable-length array instead of malloc:
int cap2[n * n]; // or int cap2[n][n], but like I said above, if you're
// treating your inputs as 1D arrays, you should also treat
// cap2 as a 1D array.
The advantage of a VLA is that you don't need to know the size at compile time, and it's treated like any other auto variable, meaning the memory for it will be released when the function exits.
The disadvantage of a VLA is that you can't use it as anything but a local variable; you can't have a VLA as a struct or union member, nor can you declare one static or at file scope. Neither can you explicitly initialize a VLA.
I understand it is not possible to pass an array to a function in C and modify it without using sending a reference to that array, so how is the chess method initialising the array, and it is being printed correctly in main?
int chess(int rows, int cols, int array[rows][cols])
{
/* Go through the rows and colums in the array */
for (int i = 0; i < rows;i++)
{
for (int j = 0; j < cols; j++)
{
/* If the location is even, then print a 0, else print a 1. */
if (((i + j) % 2) ==0)
{
array[i][j] = 0;
}
else
{
array[i][j] = 1;
}
}
}
/* return */
return 0;
}
int main(void)
{
int arrayDimensions;
int noOfTests = 7;
/* run the program for the given amount of tests */
/*for (arrayDimensions = 0; arrayDimensions <= noOfTests; arrayDimensions++)*/
{
/* Declare an array for each dimension */
int array[6][5];
/* call the chess method passing it the arguments specified. */
chess(6, 5, array);
/* Print out the array according to the size of the array. */
for (int i = 0; i < 6; i++)
{
printf("\n");
for (int j = 0; j < 5; j++)
{
printf("%d", array[i][j]);
}
}
/* Create a new line after each row */
printf("\n");
}
}
Though you probably already know most of this, the latter part is relevant, so stay with this for a moment.
What you probably know
C is a pass-by-value language. This means when you do this:
void foo(int x)
{
x = 5;
}
called as
int n = 1;
foo(n);
printf("%d\n", n); // n is still 1
the caller passes a value and the parameter x receives it. But changing x has no effect on the caller. If you want to modify a caller's data variable, you must do so by-address. You do this by declaring the formal parameter to be a pointer-to-type, dereference the pointer to modify the pointed-to data, and finally, pass the address of the variable to modify:
void foo(int *p)
{
*p = 5;
}
called as:
int n = 1;
foo(&n);
printf("%d\n", n); // n is now 5
Why do you care?
So what does any of this have to do with your array? Arrays in C are a contiguous sequence of data of the underlying type of the array, and an array's expression value is the address of its first element.
Chew on that last sentence for a minute. That means the same way an int variable has a value of the int stored within, an array variables has the address of its first element as its "value". By now you know that pointers hold addresses. Knowing that and the previous description means this:
int ar[10];
int *p = ar;
is legal. The "value" of ar is its first-element address, and we're assigning that address to p, a pointer.
Ok then, So the language specifically defined arrays as parameters as simply pointers to their first elements. Therefore both of these are equivalent:
void foo(int *p)
{
*p = 5;
}
void bar(int ar[])
{
ar[0] = 5;
}
And the caller side:
int ar[10];
foo(ar); // legal, ar's "value" is its first element address
bar(ar); // legal, identical to the above.
A phrase I often use when explaining the fundamentals of pointers and arrays is simply this:
A pointer is a variable that holds an address; an array is a variable that is an address.
So whats with this whacky syntax?
int chess(int rows, int cols, int array[rows][cols])
Ah. There is something interesting. Your compiler supports VLA s (variable length arrays). When compiling the code for this function the compiler generates the proper logic to perform the proper access to the passed array. I.e. it knows that this:
array[1][0]
is cols many int values past the beginning of the array. Without the feature of VLAs (and some C compilers don't have them), you would have to do this row-by-column math yourself by hand. Not impossible, but tedious none-the-lesss. And i only briefly mention that C++ doesn't support VLA's; one of the few features C has that C++ does not.
Summary
Arrays are passed by address because when it comes to their "value", that is all they really are: an address.
Note: I worked very hard to avoid using the word "decay" or the phrase "decays to a pointer" in this description precisely because that verb implies some mystical functional operation when in-fact none exists. Arrays don't "decay" to anything. They simply are; Their "value", per the C standard, is the address of their first element. Period. What you do with that address is another matter. And as an address, a pointer can hold their "value" and dereference to access said-same (such as a function parameter).
Personal: I once asked on this forum how long that term (decay) has been buzzed about in C-engineer vernacular, since in the 600+ pages of the C standard it appears exactly ZERO times. The farthest back anyone found was 1988 in the annals of some conspicuous online journal. I'm always curious to note who started it an where, and said-quest continues to elude me.
Anyway, I hope this helps, even a little.
when dealing with arrays you are dealing with an address so if you pass an array into a function and you changed the array in the function, the real array will change.
In other words, if you know pointers an array is a pointer.
I didn't read the code but you have a clear misunderstanding of passing an array to a function.
An array reference IS an address (it's a misnomer to say it's a pointer, but it will behave as such). It works because the function is declared to accept a type of int[][], which allows the function to interact with the array reference as if you'd passed a pointer to the function.
From a reference manual:
When a function parameter is declared as an array, the compiler treats
the declaration as a pointer to the first element of the array. For
example, if x is a parameter and is intended to represent an array of
integers, it can be declared as any one of the following declarations:
int x[]; int *x; int x[10];
So you are passing a reference. The compiler turns your declaration into a pointer reference with also some sizing constraints.
So... I have a dynamically allocated array on my main:
int main()
{
int *array;
int len;
array = (int *) malloc(len * sizeof(int));
...
return EXIT_SUCCESS;
}
I also wanna build a function that does something with this dynamically allocated array.
So far my function is:
void myFunction(int array[], ...)
{
array[position] = value;
}
If I declare it as:
void myFunction(int *array, ...);
Will I still be able to do:
array[position] = value;
Or I will have to do:
*array[position] = value;
...?
Also, if I am working with a dynamically allocated matrix, which one is the correct way to declare the function prototype:
void myFunction(int matrix[][], ...);
Or
void myFunction(int **matrix, ...);
...?
If I declare it as:
void myFunction(int *array, ...);
Will I still be able to do:
array[position] = value;
Yes - this is legal syntax.
Also, if I am working with a dynamically allocated matrix, which one
is correct to declare the function prototype:
void myFunction(int matrix[][], ...);
Or
void myFunction(int **matrix, ...);
...?
If you're working with more than one dimension, you'll have to declare the size of all but the first dimension in the function declaration, like so:
void myFunction(int matrix[][100], ...);
This syntax won't do what you think it does:
void myFunction(int **matrix, ...);
matrix[i][j] = ...
This declares a parameter named matrix that is a pointer to a pointer to int; attempting to dereference using matrix[i][j] will likely cause a segmentation fault.
This is one of the many difficulties of working with a multi-dimensional array in C.
Here is a helpful SO question addressing this topic:
Define a matrix and pass it to a function in C
Yes, please use array[position], even if the parameter type is int *array. The alternative you gave (*array[position]) is actually invalid in this case since the [] operator takes precedence over the * operator, making it equivalent to *(array[position]) which is trying to dereference the value of a[position], not it's address.
It gets a little more complicated for multi-dimensional arrays but you can do it:
int m = 10, n = 5;
int matrixOnStack[m][n];
matrixOnStack[0][0] = 0; // OK
matrixOnStack[m-1][n-1] = 0; // OK
// matrixOnStack[10][5] = 0; // Not OK. Compiler may not complain
// but nearby data structures might.
int (*matrixInHeap)[n] = malloc(sizeof(int[m][n]));
matrixInHeap[0][0] = 0; // OK
matrixInHeap[m-1][n-1] = 0; // OK
// matrixInHeap[10][5] = 0; // Not OK. coloring outside the lines again.
The way the matrixInHeap declaration should be interpreted is that the 'thing' pointed to by matrixInHeap is an array of n int values, so sizeof(*matrixInHeap) == n * sizeof(int), or the size of an entire row in the matrix. matrixInHeap[2][4] works because matrixInHeap[2] is advancing the address matrixInHeap by 2 * sizeof(*matrixInHeap), which skips two full rows of n integers, resulting in the address of the 3rd row, and then the final [4] selects the fifth element from the third row. (remember that array indices start at 0 and not 1)
You can use the same type when pointing to normal multidimensional c-arrays, (assuming you already know the size):
int (*matrixPointer)[n] = matrixOnStack || matrixInHeap;
Now lets say you want to have a function that takes one of these variably sized matrices as a parameter. When the variables were declared earlier the type had some information about the size (both dimensions in the stack example, and the last dimension n in the heap example). So the parameter type in the function definition is going to need that n value, which we can actually do, as long as we include it as a separate parameter, defining the function like this:
void fillWithZeros(int m, int n, int (*matrix)[n]) {
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
matrix[i][j] = 0;
}
If we don't need the m value inside the function, we could leave it out entirely, just as long as we keep n:
bool isZeroAtLocation(int n, int (*matrix)[n], int i, int j) {
return matrix[i][j] == 0;
}
And then we just include the size when calling the functions:
fillWithZeros(m, n, matrixPointer);
assert(isZeroAtLocation(n, matrixPointer, 0, 0));
It may feel a little like we're doing the compilers work for it, especially in cases where we don't use n inside the function body at all (or only as a parameter to similar functions), but at least it works.
One last point regarding readability: using malloc(sizeof(int[len])) is equivalent to malloc(len * sizeof(int)) (and anybody who tells you otherwise doesn't understand structure padding in c) but the first way of writing it makes it obvious to the reader that we are talking about an array. The same goes for malloc(sizeof(int[m][n])) and malloc(m * n * sizeof(int)).
Will I still be able to do:
array[position] = value;
Yes, because the index operator p[i] is 100% identical to *(ptr + i). You can in fact write 5[array] instead of array[5] and it will still work. In C arrays are actually just pointers. The only thing that makes an array definition different from a pointer is, that if you take a sizeof of a "true" array identifier, it gives you the actual storage size allocates, while taking the sizeof of a pointer will just give you the size of the pointer, which is usually the system's integer size (can be different though).
Also, if I am working with a dynamically allocated matrix, which one is the correct way to declare the function prototype: (…)
Neither of them because those are arrays of pointers to arrays, which can be non-contigous. For performance reasons you want matrices to be contiguous. So you just write
void foo(int matrix[])
and internally calculate the right offset, like
matrix[width*j + i]
Note that writing this using the bracket syntax looks weird. Also take note that if you take the sizeof of an pointer or an "array of unspecified length" function parameter you'll get the size of a pointer.
No, you'd just keep using array[position] = value.
In the end, there's no real difference whether you're declaring a parameter as int *something or int something[]. Both will work, because an array definition is just some hidden pointer math.
However, there's is one difference regarding how code can be understood:
int array[] always denotes an array (it might be just one element long though).
int *pointer however could be a pointer to a single integer or a whole array of integers.
As far as addressing/representation goes: pointer == array == &array[0]
If you're working with multiple dimensions, things are a little bit different, because C forces you declare the last dimension, if you're defining multidimensional arrays explicitly:
int **myStuff1; // valid
int *myStuff2[]; // valid
int myStuff3[][]; // invalid
int myStuff4[][5]; // valid