I just started learning functions and passing the parameters. so i am kind of new to this. Here, in the following programming, i am changing the values of a[] which is a formal parameter. even though, the sort function is not returning anything. how are the elements in numberArray[] are getting sorted even though the sort function just dealing with the formal parameters?
#include<stdio.h>
void sort(int[],int);
int main(void)
{
int n;
printf("enter the number of elements : ");
scanf("%d",&n);
int numberArray[n];
printf("enter %d numbers :\n",n);
for(int i=0;i<n;i++)
scanf("%d",&numberArray[i]);
sort(numberArray,n);
printf("sorted list of numbers are :\n");
for(int i=0;i<n;i++)
printf("%d\n",numberArray[i]);
return 0;
}
void sort(int a[],int n)
{
int i,j,temp;
for(i=0;i<n-1;i++)
{
for(j=i+1;j<n;j++)
{
if(a[i]>a[j])
{
temp=a[j];
a[j]=a[i];
a[i]=temp;
}
}
}
}
I would like to compare the above program with a simple program as follows.
#include<stdio.h>
void nothing(int);
int main(void)
{
int a;
printf("enter the value : ");
scanf("%d",&a);
nothing(a);
printf(" a = %d",a);
return 0;
}
void nothing(int b)
{
b=b+2;
}
In this program, the value of a is not changing. Why?
In C array parameters to functions are a fiction. Arrays don't get passed to functions; the parameter is treated as a pointer.
So in your example a is really an int*.
Personally, I think that function parameters declared as arrays is almost always a bad idea, since it doesn't model what is really being passed to the function. Until you understand what is really happening, it can cause confusion of the sort you ran into. It also commonly causes problems with people who try to obtain he size of the array passed to a function using the sizeof operator - that doesn't work since sizeof will return the size of a pointer type, not the actual array type.
The one situation where I think array formal arguments might make sense is with multi-dimension arrays, where the pointer arithmetic can be helpful.
Note that C99 introduced variable length arrays (VLAs) which can change much of this. VLAs are different animals, but because support for them came rather late (even after C99 was standardized, it took a while for may implementations to support them properly). This answer doesn't necessarily apply to passing VLAs as arguments to functions.
C passes by value ie
void nothing(int b) {
b=b+2;
}
is getting a copy of the integer. If you want to see the int change you need to pass it's address ie
void nothing(int *b) {
*b = *b + 2;
}
You pass the address as following
nothing(&a);
In the program you reference this function...
void sort(int a[],int n)
is taking a pointer to an array of integers as it's first argument so any change to it in the function changes the actual memory it points to
Related
I am learning recursion. As an exercise I am trying to find the maximum of an array recursively.
int recursive (int *arr, int n, int largest) {
if(n==0)
return largest;
else {
if (*(arr+n)>largest) {
largest = *(arr+n);
recursive(arr, n-1, largest);
}
}
}
int main() {
int length = n-1;
int largest = v[0];
int z = recursive(arr, length, largest);
printf("\n%d", z);
}
I followed your suggestions, using pointers instead of arrays, and probably the program looks way better. But still it is not doing it's not showing the maximum correctly. I think the logic is correct.
First thing pay attention to compiler warnings, your recursive function doesn't return value when you enter the else part.
Now the second thing is please don't use things like *(arr+n) which is hard to read instead use arr[n], also while just a preference when using arrays as function arguments use int arr[] to call the function instead of int *arr (in the first version it's clear you should pass an array).
Third thing is to name your things instead of int recursive describe what the function is doing for example int maxElemRecursive
So your recursive function should be something like
int maxElemRecursive(int arr[],int n,int largest)
{
if(n==0) return largest;
if(arr[n] > largest) // No need for else because return largest; would've returned value;
{
largest = arr[n];
}
return maxElemRecursive(arr,n-1,largest); // You have to return the value of the function.
// You still pass the array with just arr.
}
In C usually you can't declare an array whose size is unknown at compile-time, hence int v[n] is dangerous code.
Depending on your compiler and the compiler's settings this could be a compile error or it could be a bug.
For such problems you need to learn about pointers and dynamic memory allocation.
Side-note: After C99 there are stuff like Variable Length Arrays but the rules are a little advanced.
Also to pass an array to a function you give the array a pointer as an argument:
int z = recursion(v, n, v[0]);
instead of:
int z = recursion(v[n], n, v[0]);
I have created an array of function pointers to swap two variables.
pointer pointing to these functions namely: swap1, swap2. swap3 and swap4.
swap2 is swaping using pointer passed as arguments.
but while declaring the function pointer, only int and int are passed as arguments. after compiling this causes many warnings.
so do we have a better way of passing the argument, where we put condition in function call itself.
code is given below.
#include <stdio.h>
int swap1(int ,int );
int swap2(int* ,int* );
int swap3(int ,int );
int swap4(int, int);
int swap1(int a,int b)
{
int temp=a;
a=b;
b=temp;
printf("swapped with 3rd variable :%d, %d\n", a,b);
}
int swap2(int *a,int *b)
{
int temp = *a;
*a = *b;
*b = temp;
printf("swapped with pointer :%d, %d\n", *a,*b);
}
int swap3(int a,int b)
{
a+=b;
b=a-b;
a-=b;
printf("swapped with 2 variable :%d, %d\n", a,b);
}
int swap4(int a,int b)
{
a=a^b;
b=a^b;
a=a^b;
printf("swapped with bitwise operation :%d, %d\n", a,b);
}
int main()
{
int ch;
int a=3;
int b=4;
printf("enter the option from 0 to 3\n");
scanf("%d",&ch);
int (*swap[4])(int, int) ={swap1,swap2,swap3,swap4};// function pointer
/*can we pass something like int(*swap[4]( condition statement for 'pointer to variable' or 'variable')*/
if (ch==1)// at '1' location, swap2 is called.
{
(*swap[ch])(&a,&b);//passing the addresses
}
else
{
(*swap[ch])(a,b);
}
return 0;
}
some warnings are as follows.
at line 36 in file '9e748221\script.c'
WARNING: found pointer to int where int is expected
at line 47 in file '9e748221\script.c'
WARNING: found pointer to int where int is expected
at line 47 in file '9e748221\script.c'
Well yes. There are a number of problems with your code, but I'll focus on the ones to which the warnings you presented pertain. You declare swap as an array of four pointers to functions that accept two int arguments and return an int:
int (*swap[4])(int, int)
Your function swap2() is not such a function, so a pointer to it is not of the correct type to be a member of the array. Your compiler might do you a better favor by rejecting the code altogether instead of merely emitting warnings.
Having entered a pointer to swap2() into the array anyway, over the compiler's warnings, how do you suppose the program could call that function correctly via the pointer? The type of the pointer requires function arguments to be ints; your compiler again performs the dubious service of accepting your code with only warnings instead of rejecting it.
Since the arguments in fact provided are the correct type, it might actually work on systems and under conditions where the representations of int and int * are compatible. That is no excuse, however, for writing such code.
Because pointers and ints are unchanged by the default argument promotions, one alternative would be to omit the prototype from your array declaration:
int (*swap[4])() = {swap1,swap2,swap3,swap4};
That says that each pointer points to a function that returns int and accepts a fixed but unspecified number of arguments of unspecified types. At the point of the call, the actual arguments will be subject to the default argument promotions, but that is not a problem in this case. This option does prevent the compiler from performing type checking on the arguments, but in fact you cannot do this correctly otherwise.
Your compiler might still warn about this, or could be induced to warn about it with the right options, but the resulting code nevertheless conforms and does the right thing, in the sense that it calls the pointed-to functions with the correct arguments.
To deal with the warnings first: You declare an array of functions which take int parameters. This means that swap2 is incompatible with the type of element for the array you put it in. This will generate a diagnostic.
Furthermore, when you call one of the functions in the array, the same array declaration tells the compiler that the parameters need to be ints not pointers to int. You get two diagnostics here, one for each parameter.
To fix the above all your functions need to have compatible prototypes with the element type of the array. Should it be int or int*? This brings us to the other problem.
C function arguments are always pass by value. This means that the argument is copied from the variable onto the stack (or into the argument register depending on the calling convention and argument count - for the rest of this post, I'll assume arguments are placed on the stack for simplicity's sake). If it's a literal, the literal value is put on the stack. If the values on the stack are changed by the callee no attempt is made by the caller, after the function returns, to put the new values back in the variables. The arguments are simply thrown away.
Therefore, in C, if you want to do the equivalent of call by reference, you need to pass pointers to the variables you use as arguments as per swap2. All your functions and the array should therefore use int*. Obviously, that makes one of swap1 and swap2 redundant.
The correct array definition is
int (*swap[4])(int*, int*) = {swap1, swap2, swap3, swap4};
and the definition of each function should be modified to take int* parameters. I'd resist the temptation to use int (*swap[4])() simply because it circumvents type safety. You could easily forget the & in front of an int argument when the called function is expecting a pointer which could be disastrous - the best case scenario when you do that is a seg fault.
The others have done great work explaining what the problems are. You should definitely read them first.
I wanted to actually show you a working solution for that sort of problem.
Consider the following (working) simple program :
// main.c
#include <stdio.h>
void swap1(int* aPtr, int* bPtr) {
printf("swap1 has been called.\n");
int tmp = *aPtr;
*aPtr = *bPtr;
*bPtr = tmp;
}
void swap2(int* aPtr, int* bPtr) {
printf("swap2 has been called.\n");
*aPtr += *bPtr;
*bPtr = *aPtr - *bPtr;
*aPtr -= *bPtr;
}
int main() {
int a = 1, b = 2;
printf("a is now %d, and b is %d\n\n", a, b);
// Declare and set the function table
void (*swapTbl[2])(int*, int*) = {&swap1, &swap2};
// Ask for a choice
int choice;
printf("Which swap algorithm to use? (specify '1' or '2')\n>>> ");
scanf("%d", &choice);
printf("\n");
// Swap a and b using the right function
swapTbl[choice - 1](&a, &b);
// Print the values of a and b
printf("a is now %d, and b is %d\n\n", a, b);
return 0;
}
First of, if we try to compile and execute it:
$ gcc main.c && ./a.out
a is now 1, and b is 2
Which swap algorithm to use? (specify '1' or '2')
>>> 2
swap2 has been called.
a is now 2, and b is 1
As myself and others mentioned in answers and in the comments, your functions should all have the same prototype. That means, they must take the same arguments and return the same type. I assumed you actually wanted to make a and b change, so I opted for int*, int* arguments. See #JeremyP 's answer for an explanation of why.
There are tons of similar questions, but still I could not find any answer relevant for the feature of variable length arrays in C99/C11.
How to pass multidimensional variable length array to a function in C99/C11?
For example:
void foo(int n, int arr[][]) // <-- error here, how to fix?
{
}
void bar(int n)
{
int arr[n][n];
foo(n, arr);
}
Compiler (g++-4.7 -std=gnu++11) says:
error: declaration of ‘arr’ as multidimensional array must have bounds for all dimensions except the first
If I change it to int *arr[], compiler still complains:
error: cannot convert ‘int (*)[(((sizetype)(((ssizetype)n) + -1)) + 1)]’ to ‘int**’ for argument ‘2’ to ‘void foo(int, int**)’
Next question, how to pass it by value and how to pass it by reference? Apparently, usually you don't want the entire array to be copied when you pass it to a function.
With constant length arrays it's simple, since, as the "constant" implies, you should know the length when you declare the function:
void foo2(int n, int arr[][10]) // <-- ok
{
}
void bar2()
{
int arr[10][10];
foo2(10, arr);
}
I know, passing arrays to functions like this is not a best practice, and I don't like it at all. It is probably better to do with flat pointers, or objects (like std:vector) or somehow else. But still, I'm a bit curios what is the answer here from a theoretical standpoint.
Passing arrays to functions is a bit funny in C and C++. There are no rvalues of array types, so you're actually passing a pointer.
To address a 2D array (a real one, not array of arrays), you'll need to pass 2 chunks of data:
the pointer to where it starts
how wide one row is
And these are two separate values, be it C or C++ or with VLA or without or whatnot.
Some ways to write that:
Simplest, works everywhere but needs more manual work
void foo(int width, int* arr) {
arr[x + y*width] = 5;
}
VLA, standard C99
void foo(int width, int arr[][width]) {
arr[x][y] = 5;
}
VLA w/ reversed arguments, forward parameter declaration (GNU C extension)
void foo(int width; int arr[][width], int width) {
arr[x][y]=5;
}
C++ w/ VLA (GNU C++ extension, terribly ugly)
void foo(int width, int* ptr) {
typedef int arrtype[][width];
arrtype& arr = *reinterpret_cast<arrtype*>(ptr);
arr[x][y]=5;
}
Big remark:
The [x][y] notation with a 2D array works because the array's type contains the width. No VLA = array types must be fixed at compile-time.
Hence: If you can't use VLA, then...
there's no way to handle it in C,
there's no way to handle it without a proxy class w/ overloaded operator overloading in C++.
If you can use VLA (C99 or GNU C++ extensions), then...
you're in the green in C,
you still need a mess in C++, use classes instead.
For C++, boost::multi_array is a solid choice.
A workaround
For 2D arrays, you can make two separate allocations:
a 1D array of pointers to T (A)
a 2D array of T (B)
Then set the pointers in (A) to point into respective rows of (B).
With this setup, you can just pass (A) around as a simple T** and it will behave well with [x][y] indexing.
This solution is nice for 2D, but needs more and more boilerplate for higher dimensions. It's also slower than the VLA solution because of the extra layer of indirection.
You may also run into a similar solution with a separate allocation for every B's row. In C this looks like a malloc-in-a-loop, and is analogous of C++'s vector-of-vectors. However this takes away the benefit of having the whole array in one block.
There is no clear cut way for doing this but you can use a workaround to treat a 2 dimensional array as a one dimensional array and then reconvert it to a two dimensional array inside the function.
void foo2(int n, int *arr)
{
int *ptr; // use this as a marker to go to next block
int i;
int j;
for(i = 0; i < n; i++)
{
ptr = arr + i*n; // this is the starting for arr[i] ...
for (j = 0; j < n ;j++)
{
printf(" %d ", ptr[j]); // This is same as arr[i][j]
}
}
}
void bar2()
{
int arr[10][10];
foo2(10, (int *)arr);
}
#include<stdio.h>
#include<stdlib.h>
#define max 10
void init_graph(int arr[max][max],int v);
void create_graph(int arr[max][max],int v);
void print_graph(int arr[max][max],int v);
int main()
{
int v,n;
printf("Enter the number of vertices :");
scanf("%d",&v);
int arr[v][v];
init_graph(arr,v);
printf("v=%d after init\n",v);
create_graph(arr,v);
print_graph(arr,v);
return 0;
}
void create_graph(int arr[max][max],int v)
{
printf("v=%d \n",v);
int e;
printf("Enter the number of edges :");
scanf("%d",&e);
int i,src=0,dest=0;
for(i=0;i<e;i++)
{
printf("Enter Edge :%d",i+1);
scanf("%d %d",&src,&dest);
if(src<=-1 || src>=v)
{
printf("Invalid source vertex \n");
i--;
continue;
}
if(dest<=-1 || dest >=v)
{
printf("Invalid dest vertex \n");
i--;
continue;
}
//*(*(arr+src)+dest)=1;
//*(*(arr+dest)+src)=1;
arr[src][dest]=1;
arr[dest][src]=1;
}
}
void init_graph(int arr[max][max],int v)
{
int i,j;
for(i=0;i<v;i++)
{
for(j=0;j<v;j++)
{
//*(*(arr+i)+j)=0;
arr[i][j]=0;
}
}
printf("V=%d init_graph\n",v);
}
void print_graph(int arr[max][max],int v)
{
int i,j;
for(i=0;i<v;i++)
{
for(j=0;j<v;j++)
{
//printf("%d ",*(*(arr+i)+j));
printf("%d ",arr[i][j]);
}
printf("\n");
}
}
When I compiled the above program in Dev-c++ and in gcc 4.8.2 I'm getting different output. Here I'm trying to represent a graph using adjacency matrix representation.
when v is passed as parameter to the init_graph(arr,v)(in the above program), even though I'm not returning any value from the function, the value of v is becoming zero after after the function has been called.
It is working properly in Dev-c++ but I'm getting the wrong answer when compiled in gcc.4.8.2.
Screenshot of the output in Dev-c++
here v is not becoming 0
Screenshot of the output in gcc 4.8.2
and here v is becoming 0.
You are calling the function:
void init_graph(int arr[10][10], int v);
However your code is:
int arr[v][v];
init_graph(arr,v);
This causes undefined behaviour if v is not 10. The C11 standard clause is 6.5.2.2/6:
If [...] the types of the arguments after promotion are not compatible with the types of the parameters, the behavior is undefined.
Arrays of dimension X are only compatible with arrays of dimension Y if X == Y. (Bear in mind that the innermost dimension is "lost" due to the array as function parameter syntax quirk, so the innermost dimension can differ without breaking compatibility).
To fix this you should include the size in the array dimension in the function prototype:
void init_graph(int v, int arr[v][v]);
and similarly for the other functions.
Due to the way "array" function parameters are "adjusted" to pointers in C, the create_graph function really accepts a pointer to an array of length max. It is equivalent to this:
void create_graph(int (*arr)[max], int v)
That means that when you each iteration over arr[i] in the loop takes a step of size 10 ints, to the next length 10 array. But you are passing (after array decay) a pointer to an array of length v. If v is not the same as max, that is already undefined behaviour (UB). In your case, this takes you out of bounds, (that would cause UB by itself in an otherwise well defined program.)
You can only call the function with a pointer to array of length max or with an array of arrays whose inner array length is max (the latter will decay to pointer to array.)
Note that the type of platform dependent behaviour you saw is often a sign thet there is UB in the code.
In main() you define your array to be of size [v][v], but init_graph() takes an array of size [max][max]. You need to make these the same. I suggest changing main() since all your other functions also use max as the array size.
What happens is that when v is 5, your [5][5] array is laid out as 25 consecutive ints. But the function thinks the array is size [][10], with row size of 10 ints. So the moment you write to any element past [2][4] (the 25th element), you are writing past the end of the array and clobbering your stack. This is because your array in main() was defined as a local variable and is therefore located on the stack. In your case, the stack also contained the value of v, and it got overwritten with a 0. The reason the other compiler worked is probably because it located v before the array in memory instead of after it, so with that compiler it didn't happen to clobber v.
According to the other answers, calling the function with an incorrect argument invokes "undefined behavior" but I find that to be a lazy explanation ("anything can happen"). I hate it when people say that because any compiled program is a known quantity any you can determine exactly what the "undefined" behavior actually is (just step through it with a debugger). Once you learn what is going on and where your variables are located, you will start to intuitively understand when memory is getting corrupted and what code could possibly be responsible for it.
#include <stdio.h>
int ABC(int &n) // Error=> expected ')'
{
printf("n=");
scanf("%d",&n);
}
Help me, please! Thank you :)
Take a look to Question 4.11 of C-FAQ
Q: Does C even have ``pass by reference''?
A: Not really.
Strictly speaking, C always uses pass by value. You can simulate pass
by reference yourself, by defining functions which accept pointers and
then using the & operator when calling, and the compiler will
essentially simulate it for you when you pass an array to a function
(by passing a pointer instead, see question 6.4 et al.).
Another way of looking at it is that if an parameter has type, say,
int * then an integer is being passed by reference and a pointer to an
integer is being passed by value.
Fundamentally, C has nothing truly equivalent to formal pass by
reference or C++ reference parameters. (On the other hand,
function-like preprocessor macros can provide a form of ``pass by
name''.)
See also questions 4.8, 7.9, 12.27, and 20.1.
To simulate a pass by reference:
int ABC(int *n)
{
printf("n=");
scanf("%d", n);
printf("%d\n", *n);
return 0;
}
Call it using &:
int x;
ABC(&x);
You are not able to get the arguments as address using the ampersand(&). So you can use the
pointer to get the address of one variable.
int ABC(int *n)
{
scanf("%d",n);
}
While passing to that function, you have to pass the address of the variable.
int a;
ABC(&a);
The & is the address of operator, it can't be passed as argument to a function.
If you want to fix your code, you need to pass the argument n without &
#include <stdio.h>
int ABC(int n)
{
printf("n=");
scanf("%d",&n);
}
The same code i tried in c++ it worked just return a value and see hope this may give you an idea
int ABC(int &n)
{
printf("n=")
scanf_s("%d",&n);
return n;
}