Passing array to function by value or reference the same? - c

I want to know if there is any real difference; I have written code that as it feel it a passing by copy not reference but it acts as reference.
Here is the code:
#include <stdio.h>
#include <conio.h>
using namespace std;
int pause = 0;
void display(int b[5], int size){
for (int i = 0; i < size; i++){
printf("\n%d",b[i]," at:");
printf(" %d", &b[i]);
}
}
void main(){
int num[] = { 2, 4, 6, 8, 10 };
printf("\nIn main function.");
for (int i = 0; i < 5; i++){
printf("\n%d", num[i], " at:");
printf(" %d", &num[i]);
}
display(num,5);
scanf("%d", pause);
}

You cannot pass an array itself to a function at all, nor can you return one. In particular, despite the appearance of its declaration, your function display() does not receive an array as a parameter. It's declaration is 100% equivalent to this one:
void display(int *b, int size);
and this one:
void display(int b[], int size);
Expressions of array type are automatically converted to pointers in almost every context in which they can appear, so this function call:
display(num,5);
is equivalent to
display(&num[0],5);
Nevertheless, there is a potential difference to call out in this area: the expression &num is not equivalent to &num[0]. They refer to the same address, but the two expressions have different types. Passing the former would be the analog of passing the array by reference, but that expression does not have the correct type for the first argument to your display() function. A function that wants to receive &num needs to be declared differently:
void display2(int (*b)[5]);
or
void display3(int n, int (*b)[n]);
The latter requires C99, or C2011 with VLA support (which is required in C99, but optional in C2011).

Related

Changing the value of an element in a struct

I'm new to structs. I am trying to write a program that has a struct, and the struct is supposed to store a character array and its length. I want to be able change the length's value as I would be creating functions like trimming/concatenating the array. Here is a code I wrote:
#include <stdio.h>
#include <stdlib.h>
struct strstruct{
unsigned int length;
char string[20];
};
typedef struct strstruct stru;
int strleng(stru A){
int i=0;
while(A.string[i]!='\0'){
i++;
}
A.length =i;
return i;
}
int main(){
stru A = {1,
{'a','b','c','d','e','f'}
};
printf("%d %d\n",strleng(A),A.length);
return 0;
}
The value of A.length is not changing inspite of calling strleng.
(i)Why?
(ii) Is there another way to do it?
For starters the order of evaluation of arguments in a function call is unspecified.
So in this call
printf("%d %d\n",strleng(A),A.length);
the evaluation of the argument expression A.length can occur before calling the function strleng or vice versa.
Secondly the function strleng declared like
int strleng(stru A);
deals with a copy of the original object A declared in main and used as an argument. So changing the copy does not influence on the original object.
You need to pass the object by reference through a pointer to it.
unsigned int strleng( stru *A){
unsigned int i=0;
while(A->string[i]!='\0'){
i++;
}
A->length =i;
return i;
}
and in main you should write for example
unsigned int n = strleng( &A );
printf("%u %u\n", n, A.length );
Pay attention to that on one hand, the data member length is declared as having the type unsigned int
unsigned int length;
On the other hand, within your original function strleng you are using an object of the signed type int and the function return type is also int. The function should use at least the same type unsigned int instead of the type int.
Try the code below:
#include <stdio.h>
#include <stdlib.h>
struct strstruct{
unsigned int length;
char string[20];
};
typedef struct strstruct stru;
int strleng(stru* A){
int i=0;
while(A->string[i]!='\0'){
i++;
}
A->length =i;
return i;
}
int main(){
stru A = {1,
{'a','b','c','d','e','f'}
};
printf("%d %d %d\n",A.length, strleng(&A),A.length);
printf("%d \n",A.length);
return 0;
}
You will get output: 6 6 1. I should get the answer now.
At first, you need to use pointer as a parameter if you want to modify struture's value inner a fucntion.
For your question:
To most of the c compiler, the functions inner a printf function is prcessed from right to left. I think the compiler in your case is this one.
For some c compiler, it do process functions in one line from left to right.
I hope it can help you, c online compiler: https://www.onlinegdb.com/online_c_compiler.
printf("%d %d\n",strleng(A),A.length);
Firstly, Here you are passing the argument to the strleng function as a value means strleng function' parameter is a copy of A. In other words, variable A in the main function and structure variable inside the strleng function are two independent variables. So changing A.length in the strleng function will not be visible to your variable A in the main function. (There are many good online resources available about Pass by value vs. Pass by reference. You can check those for better understanding)
Most of the compilers takes each parameter of printf() from right to left. So here A.length execute first then strleng(A). So even you pass the argument by reference, it will still output 6 1.
Updated Code
#include <stdio.h>
#include <stdlib.h>
struct strstruct {
unsigned int length;
char string[20];
};
typedef struct strstruct stru;
int strleng(stru* A) {
int i = 0;
while(A->string[i] != '\0'){
i++;
}
A->length = i;
return i;
}
int main() {
stru A = {1, {'a','b','c','d','e','f'}};
printf("%d %d %d\n", A.length, strleng(&A), A.length);//6 6 1
return 0;
}

How do you pass an array to a function using pointers

I am trying to print an array through a function by using call by reference but keep getting a warning:
passing argument 1 of 'test' from incompatible pointer type [-Wincompatible-pointer-types]
I tried replacing test(&arr, n); with test(arr, n);, test(*arr, n);, test(&arr[], n);, test(*arr[], n);, test(&arr[], n);
but nothing worked, what am I doing wrong?
#include<stdio.h>
void test(int *a[], int b);
void main()
{
int arr[]={1, 2, 3, 4, 5}, i, n=5;
test(&arr, n);
}
void test(int *d[], int n)
{
int i;
for(i=0; i<n; i++)
{
printf("%d", *d[i]);
}
}
How do you pass an array to a function
Just by using a pointer of the array element type:
void test(int *a, int b);
If you then pass an array to the function:
test(arr);
... the C compiler will pass a pointer to the first element of the array (&(arr[0])) to the function.
Note that you don't use the & in this case.
Inside the function you can use array operations:
void test(int * arr)
{
arr[3] = arr[2];
}
(In your case: printf("%d\n", arr[n]);)
(This is true for any kind of pointer data type with exception of void *. The C compiler assumes that the pointer points to the first element of an array if you use array operations with pointer data types.)
"passing argument 1 of 'test' from incompatible pointer type"
As far as I know, [] in a function argument is not interpreted as array, but as pointer. For this reason, ...
void test(int *a[], int b);
... is interpreted as:
void test(int **a, int b);
... which means that the C compiler expects a pointer to an array of pointers (int *), not to an array of integers (int).
It's much simpler than that. In the example below I'm using size_t to express array size, it's an unsigned integer type specifically meant to be used for that purpose.
#include <stdio.h>
// you can use the size parameter as array parameter size
void test (size_t size, int arr[size]);
int main (void) // correct form of main()
{
int arr[]={1, 2, 3, 4, 5};
test(5, arr);
}
void test (size_t size, int arr[size])
{
for(size_t i=0; i<size; i++) // declare the loop iterator inside the loop
{
printf("%d ", arr[i]);
}
}

C - Copying array in other array as output argument

I am trying understand how pointers works in C. I am trying a simple case where an array, and a pointer to array are the arguments of a function which will copy the elements of the first one in the second one.
I have written this code
#include <stdio.h>
#define TAM 32
typedef int TablaArray[32];
void copyArray(TablaArray, TablaArray*, int);
void main(){
int t1[] = {1,2,3,4};
int t2[4];
copyArray(t1, t2,4);
for(int i = 0; i <= 3; i ++){
printf("%d - %d\n", t1[i], t2[i]);
}
}
void copyArray(TablaArray t1, TablaArray *t2, int tam){
for(int i = 0; i<tam-1; i++){
printf("%d\n", t1[i]);
*t2[i] = t1[i];
}
}
I am expecting to get something like this with the printf expression:
1 - 1
2 - 2
3 - 3
4 - 4
But definitely I don't know the way... I have been looking in stackoverflow and because I am sure this trivial question is already answered... but I didn't find it...
You need to make sure you are passing two int pointers pointing to both arrays. In your code only one of the arguments is a pointer. The code below should make it more clear:
#include <stdio.h>
void copyArray(int * arr1, int * arr2, int size);
int main(void)
{
int t1[] = {1,2,3,4};
int t2[4];
copyArray(t1, t2,4);
for(int i = 0; i <= 3; i ++)
{
printf("%d - %d\n", t1[i], t2[i]);
}
return 0;
}
void copyArray(int * arr1, int * arr2, int size)
{
for(int i = 0; i < size; i++)
{
printf("%d\n", arr1[i]);
arr2[i] = arr1[i];
}
return;
}
Edit: in what you have written, a TablaArray * is a pointer to an array of 32 ints, while you need an int *
typedef int TablaArray[32];
is bad practice
The problem is connected with array to pointer decay and then with pointer arithmetics:
Pointer decay means that if you pass an array-object of type int x[32] as argument to a function, then it "decays" to a pointer like int *, which points to the first element of the integer array. So be aware that if you pass an int x[32]-object, it's actually passed by reference (the array is not copied) and you may alter the contents of the array in the function.
Now pointer arithmetics:
Incrementing a pointer (or accessing an array through array subscripting) implicitly does pointer arithmetics, and the number of bytes added to the initial value depends on the type of the object to which the pointer points:
typedef int Array10[10];
Array10 arr = { 1,2,3,4,5,6,7,8,9,0 };
int *x = arr; // arrayOfInts decays to a pointer; x points to the &arr[0]
x++; // in terms of bytes, x is incremented by sizeof(int) bytes
int i = x[3]; // gets the int-value on the address of x + 3*sizeof(int)
Array10 *arr10ptr = arr;
arr10ptr++; // in terms of bytes, x is incremented by sizeof(Array10) bytes, which is 10*sizeof(int)
arr10ptr[3]; // 3*sizeof(Array10), i.e. 3*10*sizeof(int)
Now it should be clear why a function parameter being declared as a pointer to an array of int[32] behaves different from a function parameter being declared as an int[32].
So you could correct your program as follows, now knowing that TablaArray t2 will be a reference to the underlying array anyway:
void copyArray(TablaArray t1, TablaArray t2, int tam){
for(int i = 0; i<tam; i++){
printf("%d\n", t1[i]);
t2[i] = t1[i];
}
}
Hope it helps.
Compile with warnings enabled. If you used gcc -Wall -Werror, you would get the following errors:
luis.c:10:6: error: return type of ‘main’ is not ‘int’ [-Werror=main]
void main(){
^~~~
luis.c: In function ‘main’:
luis.c:15:19: error: passing argument 2 of ‘copyArray’ from incompatible pointer type [-Werror=incompatible-pointer-types]
copyArray(t1, t2,4);
^~
luis.c:8:6: note: expected ‘int (*)[32]’ but argument is of type ‘int *’
void copyArray(TablaArray, TablaArray*, int);
^~~~~~~~~
cc1: all warnings being treated as errors
The first one is simple, it should be int main.
The second one is a bit harder to see exactly because you used a typedef. So your prototype is now
void copyArray(int *, int (*)[32], int);
With the second value being a pointer-to-array that by itself is a construct that is not used often.
Instead, you'd just need two pointers to int here, and the size of an array should perhaps use size_t instead:
void copyArray(int *, int *, size_t);
void copyArray(int *t1, int *t2, size_t n){
for (int i = 0; i < tam; i++) {
t2[i] = t1[i];
}
}
Finally, if you use a C99, C11 compiler, it could be nice to use the variable-length arrays arrays to tell that one of the parameters tell the sizes of the arrays; for that we need to reorder the parameters:
void copyArray(size_t, int[*], int[*]);
void copyArray(size_t n, int t1[n], int t2[n]) {
...
}
void copyArray(TablaArray, TablaArray, int); // prototype
void copyArray(TablaArray t1, TablaArray t2, int tam){
for(int i = 0; i<tam; i++){
printf("%d\n", t1[i]);
t2[i] = t1[i];
}
}
this will help
// much faster
#include <string.h>
void copyArray(TablaArray t1, TablaArray t2, int tam){
memcpy(t2, t1, sizeof(t1[0]) * tam);
}
In Your Copy function you were copying the same value of T1 to T2 on the Address Of T2. you can do it with out pointers but pointers helps you to refer the Address

Passing an array to a function changes its values?

The intended result is the printing of the same values that we input, but the output is zero after the first row.
#include<stdio.h>
void display(int *q, int);
int main() {
int i,j,n;
int d[50][50];
printf("Input the order\t");
scanf("%d", &n);
for (i=0;i<=(n-1);i++) {
for (j=0;j<=(n-1);j++) {
scanf("%d", &d[i][j]);
}
}
display (d, n);
}
void display (int *q, int r) {
int i,j;
for (i=0;i<r;i++) {
for (j=0;j<r;j++) {
printf("%d\t", *(q + i*r + j));
}
printf("\n");
}
}
Your function is declared with a parameter of type int *. You are attempting to pass an argument of type int [50][50], which decays to pointer type int (*)[50]. These pointer types are incompatible. Language does not support implicit conversion from int (*)[50] to int. Your code is not a valid C program, and I'm sure your compiler told you about it.
A more meaningful thing to do would be to declare your function as
void display (int n, int q[n][n])
and access your array elements in a natural way as
q[i][j]
However, for that you will have to use true array sizes as n (i.e. 50 in your case). If you want to process a smaller sub-matrix of elements, you will have to pass its size separately.
But if you really want to use your "hack", you will have to use an explicit cast when calling your function
display ((int *) d, n);
and keep in mind that each row of your original array still contains 50 elements, as declared, regardless of the value of n. This means that inside your function you will have to use 50 as row size multiplier
void display (int *q, int r) {
int i,j;
for (i=0;i<r;i++) {
for (j=0;j<r;j++) {
printf("%d\t", *(q + i*50 + j));
}
printf("\n");
}
}
your display routine assumes that the 2D array is [n][n] whereas it is [50][50].
You have to pass the actual 2D array dimension alongside with n, the display routine cannot know the actual 2D array size.
You could declare your array dynamically like this:
printf("Input the order\t");
scanf("%d", &n);
int d[n][n];
and then avoid the warning
test.c:20:18: warning: passing argument 1 of 'display' from incompatible pointer type
display (d, n);
here by casting explicitly to 1D pointer (since you know the structure):
display ((int*)d, n);

Passing multidimensional arrays as arguments in functions in C

I am currently doing the fifteen exercise in CS50's Problem set 3. However, I am stuck in figuring out the syntax to pass a multi-dimensional array as an argument to a function. For instance, the following code (which prints out some numbers in an array) compiles and works:
#include <stdio.h>
void func(int array[], int size);
int main()
{
int size = 3;
int array[3] = {1,2,3};
func(array,size);
printf("Done\n");
}
void func(int array[], int size)
{
printf("%i %i %i\n", array[0],array[1], array[2]);
}
But this doesn't:
#include <stdio.h>
void func(int array[][], int size);
int main()
{
int size = 3;
int array[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
func(array,size);
printf("Done");
}
void func(int array[][], int size)
{
printf("%i %i %i\n", array[0][0],array[1][1], array[2][2]);
}
This is the error provided by clang:
test.c:3:20: error: array has incomplete element type 'int []'
void func(int array[][], int size);
^
test.c:13:20: error: array has incomplete element type 'int []'
void func(int array[][], int size)
Can anyone explain to me what's wrong with my syntax? I don't quite understand the error messages given to me by clang.
The function func() expects a pointer to int but you are passing a pointer to an array. Hence, the errrors.
It's because an array gets converted into a pointer to its first element when you pass it to a function.
You can change the function prototype and definition to receive a pointer to an array:
void func(int (*array)[3], int size);
int main()
{
int size = 3;
int array[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
func(array,size);
printf("Done");
}
void func(int (*array)[3], int size) {
...
}
Note that your array is initialized with size 3x3. So the array size has to 3x3 at least.
C99 allows to you pass dimensions. So you can write it like this too:
void func(int x, int y, int a[x][y]);
int main()
{
int size = 3;
int array[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
func(3, 3, array);
printf("Done");
}
void func(int x, int y, int array[x][y])
{
printf("%i %i %i\n", array[0][0],array[1][1], array[2][2]);
}
An array is not a type in C! Internally, it is always handled as a pointer, hence, a pointer to the array is passed as argument and not the array itself.
If you intend to pass arrays as arguments (and not just pointers), you should rethink your design!
If you still need to do this wrap the array into a structure and pass the structure.
struct astruct
{
int size;
int array[3];
};
A declaration like int a[][] isn't sensible, since the compiler must know the size of all dimensions (except of the outermost) to calculate the memory address on access.
I.e. if an array is declared as
int array[][a][b];
The memory address for access to
array[2][1][3];
is calculated by
base_address + (2*a*b + 1*b + 3) * sizeof int
Without knowing a and/or b, this calculation would not be possible.
Simply tell the function to expect a multi-dimensional array:
void func (int array[3][3], int size);
Or if you want the function to be completely flexible:
void func (int x, int y, int array[x][y]);
You need to specify size of array when declaring prototype as well as while defining function . Right now it is of incomplete type .
Try this instead -
void func(int array[][3], int size)

Resources