Issue with pointers using arrays in C - arrays

Working with pointers and arrays in C I've found a curious case which I don't understand why it occurs.
First, I want to describe correct case:
I've defined a function void modifyArray(int *list) where the array must be modified by reference to multiply items by 2 times (x2). Function implementation is:
void modifyArray(int *list, int arrLength){
for(int i=0; i<arrLength; i++){
*(list + i) = *(list + i) * 2; // x = x * 2
}
}
int main(int nargs, char **args) {
int list[] = {1,2,3,4,5};
modifyArray(&list, 5);
for(int i=0; i<5; i++){
printf("%d\n", *(list + i));
}
}
Output is:
2
4
6
8
10
Now I'm going to explain the incorrect case: I've defined a new data type List and modified the function to accept List instead of int * or int[] as first parameter:
typedef int List[5];
void modifyArray(List *list, int arrLength){
for(int i=0; i<arrLength; i++){
*(list + i) = *(list + i) * 2; // x = x * 2
}
}
After modification my compiler build fails because the sentence *(list + i) = *(list + i) * 2; // x = x * 2 can't multiply bacause of the following error message:
Invalid operands to binary expression ('List' (aka 'int [5]') and 'int')
I know my compiler is trying to multiply the complete array by 2, but don't know the reason.
The solution I've found is replacing *(list + 1) by *(*list + 1). I'm confused because of in second case, when I print list and *list output is a memory address (same memory address for both) instead of a memory address for list and its content for *list.
Can you explain why this is happening and what is the difference by using int * and List defined type?

When list is defined with int list[] = {1,2,3,4,5};, &list is a pointer to an array of five int. It is not appropriate to pass this for a parameter of type int *, and the compiler should have issued a warning or error for that in the first code. The proper argument would be list. Although that is an array, it will be automatically converted to a pointer to its first element, and that pointer is an int *, which is the correct type for the parameter.
When the parameter is declared as List *list, it is a pointer to an array. Then, in *(list + i), the addition is done in units of those arrays, not units of int. The result of the addition is a pointer to an array, so the result of the * in *(list + i) is an array. Then the multiplication is trying to multiply an array by two, so the compiler complains.
Instead, declare the parameter as List list. This declares it to be an array, but it will be automatically adjusted to be a pointer to an int. Because C does not support passing arrays as parameters, it automatically adjusts a declaration of a parameter as an array to be a declaration of a pointer to an array element instead, which is supported.
Also, do not write *(list + i). Use list[i]. It means the same thing but is easier to read.

Related

Array as a parameter without a length

I have a couple of questions about this code (I don't know what it does, it's from an exam).
What does it mean when the array is passed like this: nums[]? And what does nums + 1 mean? If nums is an array, what does it mean to add 1 to it?
int f(int nums[], int n){
if(n > 1) {
if(nums[0] < nums[1]) {
return 1 + f(nums + 1, n - 1);
}
else {
return f(nums + 1, n - 1);
}
}
else return 0;
}
In C arrays cannot be passed by value to a function.
If you write something like
int a[4] = {1, 2, 3, 4};
// ....
int result = f(a, 4);
// ^ The array "decays" to a pointer
What the function receives as parameters (passed by value) are a pointer to the first element of the array a and the size of the array (hopefully the correct one).
In the declaration of such a function, some use (and recommend) the notation showed in the question as a "documentation" of the fact that we want to pass an array, but it may be misleading, if the coder forgets that said parameter is just a pointer.
Given the use (purely accademic, it makes no sense to implement that algorithm as a recursive function), I'd find more descriptive the *:
int f(const int *nums, size_t n) {
// ^^^^^ ^
}
And what does nums + 1 mean?
The result of num + 1 is a pointer which points to the element immediately after the one pointed by num.
The recursive calls just traverse the array, one element at the time (note that the "size" is decreased accordingly), counting the times that two subsequent element are in increasing order. Would you be able to rewrite that function, without the recursive calls, using a loop?
int nums[] is an array of ints. The [] denote that it's an array. The int denotes that the array contains ints.
num + 1 points to the second position in the array, so the call basically calls the same function but passing the whole array minus the first element.
Maybe looking at the function from the side of the function prototype you will see more sense of this:
int f(int[], int n);
Here f() is declared to return an int and use two arguments: the first is an address of an array of int, the second is an int.
Since inside f() you may want to know how many int's are in the vector, it is common to the second argument to be number of elements in the array. Just as an example. Any similarity with the pair
int argc, char** argv
is because it is the same thing: the system builds a list of the arguments passed on the command line and constructs the argv array. And passes argc as the number of arguments in the array.
C does pointer arithmetic, in a sense that if x points to an int (x+1) points to the x plus the sizeof() an int. This is fantastic in order to abstract things like memory, registers and hardware.
In this way, when you call f() again passing 1 + the original argument you are just calling f() and passing the array beginning at the next position.
Back to your example, consider f() just
int f(int nums[], int n)
{
printf("First int is %d\n", nums[0]);
return 0;
}
where f() just writes down the first int of the block, and the code
int f(int[], int n);
int main(int arg, char** argv)
{
const int one[4] = { 1,2,3,4 };
const int other[2] = { 3,4 };
f(one, 4);
f(other, 2);
f(other + 1, 3'000);
return 0;
};
it shows
First int is 1
First int is 3
First int is 4
And you see that in the 3rd call f() gets the array other starting at 4, the second element.

Why does a 2D array behave like a 1D array of pointers instead of a 1D array of integers?

I have been researching and testing my knowledge in C (I am a new computer engineering student), and ran into a problem I cannot figure out.
When trying to pass a 2D array to a function, I learned that you cannot do so with dynamically allocated arrays, since the compiler needs to know array[][columns]. However, I learned that a 2D array is stored a 1D array, where the elements of each new row just follows the elements of the previous row. When I pass an array name to a function as a pointer to an array, this seems to be the case, and my code works fine. However, in the function where the 2D array is declared, it behaves as an array of pointers instead.
#include <stdio.h>
void printArray(int *A, int* dimA) {
for(int i = 0; i < dimA[0]; ++i) {
for(int j = 0; j < dimA[1]; ++j) {
printf("%3d", A[i*dimA[1] + j]);//This would work if the elements of A[] are the rows of a 2D array mapped into a 1D array
}
printf("\n\n");
}
return;
}
int main(){
int A[2][2] = {{1,2},{3,4}};
int dimA[2] = {2,2};//dimensions of the array
int i, j;
for(i = 0; i < dimA[0]; ++i) {
for(j = 0; j < dimA[1]; ++j) {
printf("%3d", *(A[i] + j)); //This would work if the elements of A[] are pointers
}
printf("\n\n");
}
for(i = 0; i < dimA[0]; ++i) { //Same code as printArray function
for(j = 0; j < dimA[1]; ++j) {
printf("%3d", A[i*dimA[1] + j]);//This would work if the elements of A[] are the rows of a 2D array mapped into a 1D array
}
printf("\n\n");
}
printArray(A, dimA);
return 0;
}
The following code outputs the array correctly in main() when the array is treated as an array of pointers, but not when treated as a 1D array of integers. However, when I pass the same array to the printArray function as a pointer, I can treat it as a 1D array of integers and it works. Any help would be appreciated (I already understand that I can instead use an array of pointers, but I really want to understand what the problem was). Thanks!
According to the C Standard (6.3.2.1 Lvalues, arrays, and function designators)
3 Except when it is the operand of the sizeof operator or the unary &
operator, or is a string literal used to initialize an array, an
expression that has type ‘‘array of type’’ is converted to an
expression with type ‘‘pointer to type’’ that points to the initial
element of the array object and is not an lvalue. If the array
object has register storage class, the behavior is undefined.
Thus in the first for loop
for(i = 0; i < dimA[0]; ++i) {
for(j = 0; j < dimA[1]; ++j) {
printf("%3d", *(A[i] + j)); //This would work if the elements of A[] are pointers
}
printf("\n\n");
}
the expression A[i] has the type int[2]. Being converted to pointer it has the type int *. So for each i the expression A[i] points to the first element of each "row" of the array A.
The expression A[i] + j points to the j-th element of each row. So dereferencing the pointer you get j-th element of the i-th row of the array.
In the second loop
for(i = 0; i < dimA[0]; ++i) { //Same code as printArray function
for(j = 0; j < dimA[1]; ++j) {
printf("%3d", A[i*dimA[1] + j]);//This would work if the elements of A[] are the rows of a 2D array mapped into a 1D array
}
printf("\n\n");
}
the expression A[i*dimA[1] + j] has the type int * and points to i *dimA[1] + j "row" of the array that is it points beyond the array. So the loop does not make sense.
The function declared like
void printArray(int *A, int* dimA);
is called like
printArray(A, dimA);
The second argument that has the type int[2] is indeed converted to pointer of the type int * that points to the first element of the array.
As for the first argument then it is also converted to pointer to its first element. And what is the element of the array? The element of this two-dimensional array is a one-dimensional array of the type int[2]. So pointer to an object of this type will have type int ( * )[2]
Pointers int * and int ( * )[2] are not compatible and by this reason the compiler shall issue a diagnostic message.
the correct declaration of the function should look like
void printArray(int ( *A )[2], int *dimA);
When trying to pass a 2D array to a function, I learned that you cannot do so with dynamically allocated arrays, since the compiler needs to know array[][columns].
This is true, in the sense that you cannot pass any array to a function. You cannot even express such a concept in C, though you can write code that looks like that to the casual eye. In almost every context where an expression evaluating to an array appears -- including function call expressions -- the array value is replaced by a pointer to the first array element.
It is partially true in the sense that a 2D array is an array of arrays, and the dimension of the (array) element type is is part of the overall array's type, part of the type of every element, and part of the type of a pointer to the first element. As such, that dimension must be part of the type of any function parameter to which you want to pass (a pointer to the first element of) the array.
It is most accurately characterized as false, however, even for 2D arrays both of whose dimensions are determined at run time. Since 1999, C has supported variable-length arrays (though in C11 it was made optional), and these play very nicely indeed with dynamically-allocated multi-dimensional arrays and with pointers to arrays of varying dimension:
// Dynamically allocating a 2D array of runtime-determined dimensions:
unsigned rows = calculate_number_of_rows();
unsigned columns = calculate_number_of_columns();
int (*matrix)[columns] = malloc(rows * sizeof(*matrix));
They work well for functions accepting such pointers, too:
void do_something(unsigned rows, unsigned columns, int matrix[rows][columns]);
... or, equivalently ...
void do_something(unsigned rows, unsigned columns, int matrix[][columns]);
... or ...
void do_something(unsigned rows, unsigned columns, int (*matrix)[columns]);
Those three forms are completely equivalent.
However, I learned that a 2D array is stored a 1D array, where the elements of each new row just follows the elements of the previous row.
A 2D array is an array of 1D arrays. The elements of any array are stored contiguously in memory without padding, so the layout of a 2D array of dimensions (r, c) cannot be distinguished from the layout of a 1D array of dimension r * c, but I recommend against thinking of it in the terms
you used.
When I pass an array name to a function as a pointer to an array, this seems to be the case, and my code works fine.
Do not do that. In practice, it is very likely to work exactly as you say, but you should heed the warnings emitted by your compiler -- and it definitely should be emitting warnings about that.
However, in the function where the 2D array is declared, it behaves as an array of pointers instead.
You've not presented an example of a function that would fit your description. Certainly it is possible to pass an array of pointers, but it is quite possible to pass a pointer to an array instead. See above for examples.
Compiling the code gives a warning that is a bit of a clue to what is going on:
main.c:27:27: warning: format specifies type 'int' but the argument has type 'int *' [-Wformat]
printf("%3d", A[i*dimA[1] + j]);//This would work if the elements of A[] are the rows of a 2D array mapped into a 1D array
~~~ ^~~~~~~~~~~~~~~~
main.c:32:16: warning: incompatible pointer types passing 'int [2][2]' to parameter of type 'int *' [-Wincompatible-pointer-types]
printArray(A, dimA);
^
main.c:3:22: note: passing argument to parameter 'A' here
void printArray(int *A, int* dimA) {
When you declare your array:
int A[2][2] = {{1,2},{3,4}};
this is stored as one contiguous chunk of memory, as you stated. In memory, this is equivalent to:
int A[4] = {1,2,3,4};
However, whenever you go to lookup/dereference the values, depending on the type, the compiler is implicitly doing some bookkeeping for you. For the second case:
int A[4] = {1,2,3,4};
A[0] = *(&A + 0) = 1
A[1] = *(&A + 1) = 2
...
fairly straightforward, the index is simply an offset off the base address. However, for the first case:
y x
int A[2][2] = {{1,2},{3,4}};
y x
A[0][0] = *(&A + 2 * 0 + 0) = *(&A + 0) = 1
A[1][0] = *(&A + 2 * 1 + 0) = *(&A + 2) = 3
...
things start to look a bit confusing.
The first thing to note is that since the type is declared as an int[2][2], you must dereference it twice. That is what the first warning is complaining about. Because it was only dereferenced once, your int ** became an int *, which is not the same as an int.
The second thing to notice is because the type is declared as a multi-dimensional array, the compiler will do some bookkeeping for you. Since the array was being dereferenced on the first dimension, the size of the second dimension to stride to the correct location was already taken into account, so instead of col * j + i, you actually got col * (col * j + i) + i, which is not what you want!
To get the desired effect, you can either:
Cast A into an int *. This is what happened when you called your printArray function, and also why it works.
Access the array from the lowest dimension. Instead of saying A[i*dimA[1] + j], do A[0][i*dimA[1] + j]. This will correctly dereference to an int and also effectively bypass the bookkeeping.

Trouble working with 2d array passed by reference C

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.

Why is there an asterisk after a function type declaration in C?

My question is in the title and is more of a syntax related question. Does anyone know what the * is doing in the function below? See here:
int* reat(int *n)
{
int i, *array;
do
{
printf("n="); scanf("%d", n);
} while (*n < 1);
array = (int *)malloc(*n * sizeof(int));
for (i = 0; i < *n; i++)
{
printf("%d. broj: ", i + 1);
scanf("%d", array + i);
}
return array;
}
The syntax
int i, *array;
declares i to be a variable of type int and array to be a variable of type int*. This sort of declaration isn't particularly common, but is legal C code.
Hope this helps!
The * in int* reat(int *n) indicates in the return that this function is returning a pointer to an integer value rather than the integer value itself. The * indicates in the argument list that this function also wants a pointer to an integer value rather than a "raw" integer value for its argument.
For example,
int x = reat(n); // assume n is a pointer to an int
probably won't compile on most systems. If it does, you'll be storing a memory address in x rather than the integer value you were expecting. Instead write
int *x = reat(n)
to store in x the pointer (to some integer value) returned by reat(). Consider this function:
int addone(int x) {
return 1 + x;
}
This function takes an integer value for its argument. To access the value of the integer pointed to by the return from reat() and use it in addone(), we'll need to call it like so:
int *x = reat(n)
addone(*x)
Thereby dereferencing x with the * operator to access the integer value it points to. addone(x) won't compile because x, without dereferencing, is a memory address and not an integer.
Understanding when the * is being used to define a pointer and when its being used to dereference one will become second nature over time. Trust that any time it shows up in a function definition, whether as an argument or a return, it indicates a pointer is being used.

Assigning pointer from two-dimensional array

#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int ar[2][2] = {1,2,3,4};
int **p= NULL , i=0, j=0;
p = ar; //compiler error. Confused ! Do i need to assign &a or anything.
puts("OUT: ");
for(i = 0; i < 2; i++)
{
for(j = 0 ; j < 2; j++)
{
printf("%2d", *(*(ar + i) + j));
printf("%2d", *(*(p + i) + j)); /* This is wrong . Compiler error */
}
}
exit(0);
}
I want to create a pointer to the 2D array so that instead of ar in the for loop
i should be able to put p. I'm confused. I know other methods of accessing 2d
elements but i'm confused with this example.
ar[2][2] will NOT decompose into pointer to pointer int **p=ar //is wrong,It will be decomposed into Pointer to first row(if we think in matrix form, which i think its easy),this means in your example your 2-d array consists of 2 rows,Each row has 2 integers(columns).
Hence ar will be decomposed into pointer to 2 integers, Which can be programmatically declared as
int (*p)[2]; //this is pointer to 2 ints
int (*p)[3]; //this is pointer to 3 ints,if your array was declared like this ar[2][3]
So in your program you need to change int **p=NULL to int (*p)[2];
When we say a pointer to 2 integers,it means that When you add one (ex:- p+1) for above example then this will point to the next two integers of 2-d array(which means next row).
In the first case you have an array of int[2], while in the second case you have an array of int*.
If you use sizeof(ar[0]), it would print 2*sizeof(int), while the second would print sizeof(int*).
printf("sizeof(ar) = %zu\n", sizeof(ar));
printf("sizeof(ar[0]) = %zu\n", sizeof(ar[0]));
printf("sizeof(ar[0][0]) = %zu\n", sizeof(ar[0][0]));
printf("sizeof(p) = %zu\n", sizeof(p));
printf("sizeof(*p) = %zu\n", sizeof(*p));
printf("sizeof(**p) = %zu\n", sizeof(**p));
Since I tried you code, replaced p = a with p = ar I only have these errors:
$ gcc -Wall foobar.c
foobar.c: In function ‘main’:
foobar.c:6:3: warning: missing braces around initializer [-Wmissing-braces]
foobar.c:6:3: warning: (near initialization for ‘ar[0]’) [-Wmissing-braces]
foobar.c:12:5: warning: assignment from incompatible pointer type [enabled by default]
foobar.c:21:7: warning: too many arguments for format [-Wformat-extra-args]
And it fails too:
$ ./a.out
sizeof(ar) = 16
sizeof(ar[0]) = 8
sizeof(ar[0][0]) = 4
sizeof(p) = 8
sizeof(*p) = 8
sizeof(**p) = 4
OUT:
Segmentation fault
Which is normal, assuming p is not so well defined.
a quote from comp.lang.c FAQ list, Question 6.18
The rule (see question 6.3) by which arrays decay into pointers is not
applied recursively. (Once the rule has been applied once, the result
is a pointer to which the rule no longer applies.) An array of arrays
(i.e. a two-dimensional array in C) decays into a pointer to an array,
not a pointer to a pointer.
int ** and int [2][2] are not compatible. you should think of your ar array as of an array that holds another arrays. multidimensional arrays allocated on stack are stored in memory continguously.
statement int ar[2][2] will be changed by the compiler to int (*ar)[2]. notice the placement of parentheses. this is because of operators precedence:
() operator has higher precendece than [] operator
[] operator has higher precedence than * operator.
. so if you would omit them, then:
int *ar[2]; // ar is an array of length 2 that holds pointers to ints.
int (*ar)[2]; // ar is a pointer to array of length 2 that hold ints.
you can resolve your problem by:
changing int **p = NULL; to int (*p)[2];
changing int ar[2][2] to int **ar and then properly allocate memory for rows and columns using malloc()
think of how that 2d array is subscripted. for example, the statement:
printf("%2d ", *(*(ar + 1) + 1)); // print the ar[1][1]
adds 1 to ar pointer, which points to int [2]. 8 bytes are added to the address of beginning of array, then after dereference adding 1 will add only 4 bytes, since it refers now to int.
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
int main(void)
{
const int row=4, col=4;
int ar[row][col] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
int **p= NULL ;
int *np = &ar[0][0];
p = &np;
for(int i = 0; i < row; i++)
{
for(int j = 0 ; j < col; j++)
{
printf("address of a[%d][%d] is %x\n",i,j,&ar[i][j]);
printf("%2d\n", *(*(ar + i) + j));
printf("%2d\n", *(*(p)+ i*col + j));
}
}
_getch();
exit(0);
}
i tried like this, it worked for me.

Resources