Passing a pointer to an array in a function in C - c

I need to write a program that implements 3 ways of passing an array to a function.
2 functions work as intented, but I am having issues with the function that passes a pointer.
I tried googling it, and testing other way, but I don't seem to understand how those pointers should work out.
First function should output 1, 2, 3.
Second function should output 11, 12, 13
Third function should output 101, 102, 103
First and third function work, but the issues is with the second one.
Here's what I wrote:
int main(void)
{
int iArray[3] = {100,234,567};
f1(iArray);
f2(iArray);
f3(iArray);
return EXIT_SUCCESS;
}
void f1(int ia[3]) // sized array
{
ia[0] = 1;
ia[1] = 2;
ia[2] = 3;
for (int i = 0; i < 3; i++)
{
printf("%d\n", ia[i]);
}
printf("\n");
}
void f2(int* pi) // pointer
{
*pi = 11, 12, 13;
printf("%d", *pi);
printf("\n\n");
}
void f3(int ia[]) // unsized array
{
ia[0] = 101;
ia[1] = 102;
ia[2] = 103;
for (int i = 0; i < 3; i++)
{
printf("%d\n", ia[i]);
}
}

In C you can't pass an array, only pointers to their elements. That means for all arguments like int ia[] the compiler really treats it as int *ia. Any potential "array" size is irrelevant, all your functions are taking the exact came int * type argument.
This is because arrays naturally decay to pointers to their first elements.
In fact, the function calls
f1(iArray);
f2(iArray);
f3(iArray);
are actually equal to
f1(&iArray[0]);
f2(&iArray[0]);
f3(&iArray[0]);
Now for the problem with the second function, it's this line:
*pi = 11, 12, 13
That is equivalent to:
pi[0] = 11, 12, 13;
which is using the comma operator which makes it equivalent to:
pi[0] = 13;
To assign each element of the array you need to index each element just like you do with the "array" functions:
pi[0] = 11;
pi[1] = 12;
pi[2] = 13;
Of course you need to print the values the same way as well, with a loop.

The syntax for referencing pointers is the same as for an array:
pi[0] = 1;
pi[1] = 2;
pi[2] = 3;
You'll also want to change the printf loop accordingly.

Related

Error expected identifier or '(' int &arrayreturn[I] = {I}

#include "stdio.h"
int printsomething(int *array, int arrayreturn[5]) {
int i;
for(i = 0; i < 10; ++i) {
printf("%d\n", array[i]);
}
for(i = 0; i < 5; ++i) {
int &arrayreturn[i] = {i};
}
return 0;
}
int main() {
int array[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
// int *arraypointer = &array;
int arrayp[5];
int i;
printsomething(array, arrayp);
for(i = 0; i < 5; ++i) {
printf("%d\n", arrayp[i]);
}
return 0;
}
I am learning C and right now just playing with arrays and pointers trying to get comfortable. This bit of code has the goal of passing an array to a function, which was successful before I added the second part. That second part being assigning values in the called function to an already initialized array. Since we can't directly return an array I understood this was the way to do it. What exactly do you all think is going wrong here? And I just completely off the target?
If you want to assign values to the array elements you need to use [] to access the elements and = to assign them. I cannot really explain your code because it is unclear how you came to the conclusion that you need to write int &arrayreturn[i] = {i};. Your loop can be this:
for(i = 0; i < 5; ++i) {
arrayreturn[i] = i;
}
the first problem is that when you have a parameter of the form int arrayreturn[5] you actually just pass an int pointer not an entire array of 5 elements. int arrayreturn[5] and int *arrayreturn compile to exactly the same cpu instructions. I never use the int arrayreturn[5] syntax because i think it is confusing so i rather just pass a pointer and this is common practice as far as i know.
secondly in the second part of your code you try to declare a new array of size i by calling int &arrayreturn[i] = {i} this is not possible because of multiple reasons mostly because you cant dynamically allocate arrays on the stack. it should be arrayreturn[i] = i

How can I use int** to pass a 2D array in C

Trying to work on leetcode #497 in C on my vscode. When writing main(), I am not sure how to deal with int** that leetcode provides. Is it possible to pass a 2D array using int**?
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int rectsSize;
int * rectsColSize;
int** rects;
} Solution;
int points[100];
Solution* solutionCreate(int** rects, int rectsSize, int* rectsColSize) {
Solution* sol = malloc(sizeof(Solution));
sol->rects = rects;
sol->rectsSize = rectsSize;
sol->rectsColSize = rectsColSize;
//some codes
}
return sol;
}
int* solutionPick(Solution* obj, int* retSize) {
//some codes
return ret;
}
void solutionFree(Solution* obj) {
free(obj);
}
int main(void)
{
int rects[2][4] = {{1, 1, 5, 5}, {6, 6, 9, 9}};
int rectsSize = 2;
int rectsColSize = 4;
int retSize;
Solution* obj = solutionCreate(rects, rectsSize, &rectsColSize);
int* param_1 = malloc(sizeof(int));
param_1 = solutionPick(obj, &retSize);
solutionFree(obj);
return 0;
}
While in general there are many different ways to handle 2D array, the simple answer is no. There is a lot of info about 2d arrays in C: 1, 2, 3, etc. In principle, when dealing with 2d arrays, every dimension except first to the left needs to be specified exactly. In your case, every rectangle is defined by 4 integers, so instead int** rects consider int*[4] rects. This makes rectsColSize useless, because now each column has constant size of 4 ints.
Just for completness: what you are trying to do is second approach to arrays, where each column has independent size, and (usually) additional malloc call. While this approach is also valid and requires int** type, it is not needed for your task. Nice description of the difference here.
Edit
Here is how to loop through 2d arrays:
#define col 4
void print_2d(int (*a)[col], int aSize){
for(size_t i = 0; i < aSize; i++){
for(size_t j = 0; j < col; j++){
printf("%d ", a[i][j]);
}
printf("\n");
}
}
and here for int**:
void print_pp(int** a, int aSize, int* aiSize){
for(size_t i = 0; i < aSize; i++){
for(size_t j = 0; j < aiSize[i]; j++){
printf("%d ", a[i][j]);
}
printf("\n");
}
}
It seems that you want to convert int*[4] to int**, or more precisely, int*[4] arr2d with it's size int arr2dSize to structure Solution. In that case, here is wrapper to solutionCreate.
Solution* solutionCreateWrap(int (*arr2d)[4], int arr2dSize) {
int* rectsColSize = malloc(arr2dSize * sizeof(int));
int** rects = malloc(arr2dSize * sizeof(int*));
size_t arr2dMem = arr2dSize * 4 * sizeof(int);
rects[0] = malloc(arr2dMem);
memcpy(rects[0], arr2d, arr2dMem);
rectsColSize[0] = 4;
for(size_t i = 1; i < arr2dSize; i++){
rects[i] = rects[0] + i*4;
rectsColSize[i] = 4;
}
sol->rects = rects;
sol->rectsSize = rectsSize;
sol->rectsColSize = rectsColSize;
//some codes
}
return solutionCreate(rects, arr2dSize, rectsColSize);
}
Now for int rects[2][4] = {{1, 1, 5, 5}, {6, 6, 9, 9}}; call solutionCreateWrap(rects, 2) will return initialised structure Solution. It looks gruesome, and it's details are even worse, so if it just works, you may skip the explanation. Understanding low level C details isn't neccesarily to write in it, and this (or any other) explanation cannot possibly cover this matter, so don't be discouraged, if you won't get it all.
arr2d is contiguous block of memory of arr2dSize*4 integers. When multiplied by sizeof(int) we get size in bytes - arr2dMem in my code. Declaration int (*arr2d)[4] means, that arr2d is of type int*[4]. Knowing this we can cast it to int* like so: int* arr = (int*)arr2d and expression arr2d[i][j] is translated as arr[i*4+j].
The translation to rects is as follows; int** is array of pointers, so every rect[i] has to be pointer to i-th row of arr2d. Knowing this, everything else is pointer arithmetic. rects[0] = malloc(arr2dMem); and memcpy(rects[0], arr2d, arr2dMem); copies whole arr2d to rect[0], then every next rects[i] = rects[0] + i*4; is shifted 4 integers forward. Because rect is of type int**, the expression rects[i][j] translates to *(rects[i]+j), and replacing rects[i] by rects[0] + i*4, we get *((rects[0] + 4*i)+j), that is rects[0][4*i+j]. Note striking similarity between last expression, and arr[i*4+j]. rectsColSize is somewhat superfluous in this case, but it is essential in general int** array, when every subarray could have different sizes. After wrap function is done, rects is exact copy of arr2d, but with type appropriate for your Solution structure, so we can call solutionCreate().

pointer arithmetic with pointer to array

I'm trying to do pointer arithmetic with a pointer to array, but I get a wrong value since I can't dereference the pointer properly.
Here is the code:
#include "stdlib.h"
#include "stdio.h"
int main()
{
int a[] = {10, 12, 34};
for (int i = 0; i < 3; ++i)
{
printf("%d", a[i]);
}
printf("\n");
int (*b)[3] = &a;
for (int i = 0; i < 3; ++i)
{
printf("%d", *(b++));
}
printf("\n");
return 0;
}
In the second for I can't get to print the correct value.
It doesn't work even if I write
printf("%d", *b[i]);
I'd like to see how to print correctly using the b++ and the b[i] syntax.
The following should work:
printf("%d\n", *( *b+i ));
// * b + i will give you each consecutive address starting at address of the first element a[0].
// The outer '*' will give you the value at that location.
instead of:
printf("%d", *(b++));
You have declared b to be a pointer to arrays of 3 integers and you have initialized it with address of a.
int (*b)[3] = &a;
In the first loop you will print the first element of a array but then you will move 3*sizeof(int) and trigger undefined behavior trying to print whatever there is.
To print it correctly:
int *b = a;
// int *b = &a[0]; // same thing
// int *b = (int*)&a; // same thing, &a[0] and &a both points to same address,
// though they are of different types: int* and int(*)[3]
// ...so incrementing they directly would be incorrect,
// but we take addresses as int*
for (int i = 0; i < 3; ++i)
{
printf("%d", (*b++));
}
gcc will complain about the formatting in the second for loop: it will tell you format specifies type 'int' but the argument has type 'int *
your assignment of a to b should look like this:
int *b = a

Arguments and returning array in C

I am new to C and I am learning from "Programming in C" by Stephen G. Cochan. I have been given next exercise:
12.A matrix M with i rows, j columns can be transposed into a matrix N having j rows
and i columns by simply setting the value of N a,b equal to the value of M b,a for all
relevant values of a and b.
a) Write a function transposeMatrix that takes as an argument a 4 x 5 matrix
and a 5 x 4 matrix. Have the function transpose the 4 x 5 matrix and store
the results in the 5 x 4 matrix. Also write a main routine to test the function.
I have done something wrong with the arguments.
The errors I'm getting are:
warning: return makes integer from pointer without a cast [enabled by default]
passing argument 1 of ‘transposeMatrix’ makes pointer from integer without a cast [enabled by default]
expected ‘int (*)[5]’ but argument is of type ‘int’ (It seems to me like this can be ignored)
etc..all about arguments..
I know code is not perfect but i think it should work if array was returned correctly and arguments were fixed..but I can't find a way to fix it..
// Program to transpose M matrix to N matrix
#include <stdio.h>
int transposeMatrix(int matrixM[][5], int matrixN[][4]) {
int i, j;
i = 0;
j = 0;
for (i = 0; i < 4; i++) {
for (j = 0; j < 5; j++) {
matrixN[j][i] = matrixM[i][j];
}
}
return matrixN;
}
int main(void) {
int i, j;
int matrixM[4][5] = {{12, 25, 47, 87, 54},
{16, 89, 78, 63, 58},
{45, 21, 47, 62, 82},
{14, 56, 47, 41, 98}};
int matrixN[5][4];
transposeMatrix(matrixM[4][5], matrixN[5][4]);
i = 0;
j = 0;
for (j = 0; j < 5; j++) {
for (i = 0; i < 4; i++) {
printf("%i ", matrixN[j][i]);
}
printf("\n");
}
return 0;
}
There are two ways a function can pass data back to the caller:
Returning a value, and
Changing a data structure a pointer to which is passed to the function as an argument
The first way involves copying, and is inefficient for larger values. The second way is preferred when a large value needs to be returned without copying, or when you need to return multiple results.
Another problem is passing the arrays: your call should pass array names without indexes, like this:
transposeMatrix(matrixM,matrixN);
Your code is using the second strategy. However, it does not need to return anything else. Therefore, the proper return type for your function should be void, not int. Change the return type, and remove the return statement to fix this issue.
Demo on ideone.
Actually the code linked above doesn't really work, it's just printing a transposed matrix by switching rows with columns in the printf() call, it does not truly transpose the matrix as the exercise requires (you can avoid calling transposeMatrix at all and the result is the same). Pay attention to how the exercise is worded, you should use a function and store the results in a new matrix. Also, at this point in the book we're not supposed to use pointers (yet).
This is how I did it:
/*
A matrix M with i rows, j columns can be transposed into a matrix N having j rows and i columns
by simply setting the value of Na,b equal to the value of Mb,a for all relevant values of a and b.
Write a function transposeMatrix() that takes as an argument a 4 × 5 matrix and a 5 × 4
matrix. Have the function transpose the 4 × 5 matrix and store the results in the 5 × 4 matrix. Also
write a main() routine to test the function.
*/
#include <stdio.h>
void transposeMatrix(int matrix45[4][5], int matrix54[5][4])
{
int x, y;
for (x = 0; x < 4; x++)
for (y = 0; y < 5; y++)
matrix54[y][x] = matrix45[x][y];
}
int main(void)
{
int x, y;
int myMatrix[4][5] = { {0, 1, 2, 3, 4},
{5, 6, 7, 8, 9},
{10, 11, 12, 13, 14},
{15, 16, 17, 18, 19} };
int myTransposedMatrix[5][4];
printf("Original Matrix: \n\n");
for (x = 0; x < 4; x++)
{
for (y = 0; y < 5; y++)
{
printf("%3i", myMatrix[x][y]);
}
printf("\n");
}
transposeMatrix(myMatrix, myTransposedMatrix);
printf("\nTransposed Matrix: \n\n");
for (x = 0; x < 5; x++)
{
for (y = 0; y < 4; y++)
{
printf("%3i", myTransposedMatrix[x][y]);
}
printf("\n");
}
return 0;
}

Lvalues, Rvalues and Array Initialisation in C

Being able to define an array e.g.
int a[] = {1,2,3};
is very convenient, however, the array a is an r-value so I can't subsequently change the values in a, e.g.
a[] = {4,5,6};
The context for wanting to do this is writing a bunch of unit tests where I am feeding in arrays to functions and testing the outputs. I'm running tests on the same function with different inputs and would like to avoid having to have unique names for my input arrays, e.g. I'm having to do this:
int test1_a[] = {1,2,3};
/* calls to functions */
int test2_a[] = {4,5,6};
/* calls to functions */
Also, if I want to pass a pointer to an array into a function I have to 1st cast it like this:
int a[] = {1,2,3};
int *b = a;
my_func(&b);
passing a pointer to an r-value like this doesn't work:
my_func(&a);
My question is whether there is any other way to easily initialise an array of values without suffering from these limitations? (particularly with a view to making it easy to write many similar unit tests without each test having a unique set of array names)
If you already have the values you want to pass to the functions, why not use a multi-dimensional array?
int a[][] = {
{ 1, 2, 3 },
{ 4, 5, 6 }
}
for (int i = 0; i < 2; i++)
{
/* Call functions with 'a[i]' as argument */
}
Also, if the functions you call expect an array, and you have a e.g. int a[] = {...}; int *b = a;, then don't call them with &b. Using &b passes the address of the pointer, not what it points to.
If i have understood your question properly.I guess the following should solve your problem.
memcpy(a, (int[]){3, 2, 1}, sizeof a);
Only if your c compiler supports compound literals(c99 onwards).
To specify the standard, gcc can be invoked as "gcc -std=c99 -Wall -pedantic".
Here's one option:
#include <stdio.h>
#include <stdarg.h>
void ReinitArray(int* p, size_t cnt, ...)
{
va_list ap;
va_start(ap, cnt);
while (cnt--)
{
*p++ = va_arg(ap, int);
}
va_end(ap);
}
int array[5] = { 1, 2, 3, 4, 5 };
int main(void)
{
size_t i;
printf("array[5]=");
for (i = 0; i < 5; i++) printf("%d ", array[i]);
printf("\n");
ReinitArray(array, 5, 11, 22, 33, 44, 55);
printf("array[5]=");
for (i = 0; i < 5; i++) printf("%d ", array[i]);
printf("\n");
return 0;
}
Output:
array[5]=1 2 3 4 5
array[5]=11 22 33 44 55
And you can simply write my_func(a); where a is an array name. This will be equivalent to passing &a[0], the address of the very first array element. You can't pass entire arrays directly as function parameters in C.

Resources