Here I'm getting the output 'bcde' but since 'a' is a constant array pointer it should not have been incremented inside fun() right? Then why is it allowed here?
void fun(char a[])
{
a++;
printf("%s",a);
}
void main()
{
char a[]="abcde";
fun(a);
}
When you pass an array to a function in C, the array "decays" to a pointer. In other words, an equivalent function can be declared like this:
void fun(char *a)
Now the code inside the function makes perfect sense: the pointer is incremented, so when the result is passed to printf, the original string is printed starting with the second letter.
When you pass an array name to your function then you are passing pointer to its first element.
void fun(char a[]) // a is not an array of char
is equivalent to
void fun(char *a)
You can modify a inside function because it is not an array name but a pointer to char.
You can't modify a in main as it is declared as array. Array names are non modifiable l-values.
When you are in function arguments, char a[] is treated exactly as if you wrote char *a.
There is no any "constant array pointer"
In this statement
char a[]="abcde";
there is declared a non-const array. You may change it for example as
a[0] = 'A';
When you pass the array to the function as an argument then there is used conversion from the array to a pointer of type char * that points to the first element of the array.
This function declaration
void fun(char a[]);
is equivalent to
void fun(char *a);
The parameter is adjaced to the pointer.
So inside the function you can to change the pointer itself and the object it points to. For example
a++;
*a = 'B';
If you want that the pointer would not be changed in the function you could declare it as
void fun(char * const a);
In this case the compiler would issue an error for statement
a++;
because a is indeed a const pointer.
Related
Please read the comments in the program below :
#include<stdio.h>
void test(char c[])
{
c=c+2; //why does this work ?
c--;
printf("%c",*c);
}
int main()
{
char ch[5]={'p','o','u','r'};
//ch = ch+2; //this is definitely not allowed on array names as they are not pointers
test(ch);
return 0;
}
OUTPUT
o
You should keep in mind that the name of the array "decays" to a pointer to its first element. This means that test(ch); is equivalent to test(&ch[0]);.
Also, void test(char c[]) is nothing but void test(char* c), a pointer to a character. Pointers can be incremented or decremented which is why c = c + 2 and c-- compiles just fine.
Array designators are immutable lvalues. That is you may not change an array designator such a way that ir would define another array.
Consider array designators as named memory extents.
As for your example then this function declaration
void test(char c[]);
is adjusted by the compiler the following way
void test(char *c);
that is a parameter having an array type is adjusted by the compiler to pointer. Thus for example these function declarations
void test(char c[100]);
void test(char c[10]);
void test(char c[1]);
void test(char c[]);
are equivalent and declare this one function
void test(char *c);
You nay include all these declarations in your program though they will be redundant.
For example
#include <stdio.h>
void test(char c[100]);
void test(char c[10]);
void test(char c[1]);
void test(char c[]);
void test( char *c)
{
c=c+2;
c--;
printf("%c",*c);
}
int main( void )
{
char ch[5]={'p','o','u','r'};
test(ch);
}
To make it evident consider the following program
#include <stdio.h>
void test( char c[] )
{
printf( "sizeof( c ) = %zu\n", sizeof( c ) );
}
int main( void )
{
char ch[5]={'p','o','u','r'};
test( ch );
printf( "sizeof( ch ) = %zu\n", sizeof( ch ) );
}
Its output is
sizeof( c ) = 8
sizeof( ch ) = 5
That is within the function sizeof( c ) is equal to the size of a pointer (in used system it is equal to 8). While in main sizeof( ch ) is the size of the array.
When you pass an array to such a function then the array designator is implicitly converted to pointer to its first element. So these calls
test( ch );
test( &ch[0] );
are equivalent.
This means that within the function you deal with a pointer and you can change the value of the pointer using the pointer arithmetic.
When an array is passed as function argument (among other cases), it decays to a pointer to the first element, and the function parameter which receives it is local to the function scope.
Quoting C11, chapter §6.3.2.1
Except when it is the operand of the sizeof operator, the _Alignof 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. [...]
So, in your case, inside void test(char c[]) function call, c is just another pointer, which points to the first element of the array. Normal pointer arithmetic can be performed on that pointer.
In other words,
void test(char c[]) { //....
is same as
void test(char *c) { //....
So, you case is something similar to
int main(void) //correcting the definition
{
char ch[5]={'p','o','u','r'};
//ch = ch+2; //this is definitely not allowed on array names as they are not pointers
char *c = &ch[0]; // this is what happens when you pass the array as function argument.
c = c + 2; // see, this is possible.
test(ch);
return 0;
}
In declarations of function parameters, an array declaration is automatically adjusted to be a pointer declaration, per C 2018 6.7.6.3 7:
A declaration of a parameter as “array of type” shall be adjusted to “qualified pointer to type”,…
Thus void test(char c[]) is effectively void test(char *c).
In main, ch is an array, because it was declared with char ch[5]…, which is a normal declaration that is not adjusted. In test, c is a pointer.
When main calls test with test(ch), the argument ch is an expression. In an expression, an array is automatically converted to a pointer in most cases because C 2018 6.3.2 3 says:
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…
Thus, when an array is passed to a function with a parameter declared as an array, the array is converted to a pointer and is passed for a parameter that was adjusted to be a pointer.
Note that only an outer array is adjusted. If the function parameter declaration is int x[3][4], it is adjusted to be int (*x)[4], a pointer to an array of 4 int. Only the array that is the parameter (the array of 3 arrays of 4 int above) is adjusted; other types within its composition are not adjusted.
Aside
The C standard is not entirely clear about the effects of the adjustment. Using Apple LLVM 10.0.1 with clang-1001.0.46.4, the following program prints “Hello, world.”:
#include <stdio.h>
static void foo(int a[printf("Hello, world.\n")]) {}
int main(void) { foo(0); }
This shows the array declaration was not completely adjusted to be a pointer declaration, as the expression specifying the array size was retained but would not be present in a pointer declaration.
Is there any difference between two function in C?
void f1(int arr[]) {
//some code...
}
void f2(int arr[10]) {
//some code
}
What will be the size of first array in f1 function?
Is there any difference between two function in c?
No difference here. Both will be interpreted as int *arr by the compiler as arrays are converted to a pointer to its first element when used as a function parameter.
what will be the size of first array in f1 function?
Strictly speaking, there is no array here. Its only pointer to an int. If you will use sizeof(arr), then you will get the value equal to sizeof(int *).
The array size in parameters are needed when the type of parameter is a pointer to an array. in this case you need to have specify the size of array as each size makes the pointer to point to different type.
void f3(int (*arr)[10]); // Expects a pointer to an array of 10 int
When an array is passed to a function, it decays into a pointer to the first element of the array.
So this:
void f1(int arr[])
And this:
void f1(int arr[10])
And this:
void f1(int *arr)
Are all equivalent.
In fact if you passed int a[20] to a function declared to take int arr[10], gcc won't complain.
I'm reading K&R and have a problem here. I don't know how this function is changing the value of the calling variable. Shouldn't this be call by value, not call by reference since to[] and from[] aren't explicity declared as pointers? The value of foo is changed to "Testing".
#include <stdio.h>
void copy(char to[], char from[]) {
int i = 0;
while ((to[i] = from[i]) != '\0') i++;
}
int main() {
char foo[] = "";
char bar[] = "Testing";
copy(foo, bar);
printf("%s\n", foo);
return 0;
}
Also, why isn't this arr_alter function changing the value of test_arr? It seems that looping through each element in the array changes the value of the calling variable yet this does not.
#include <stdio.h>
void arr_alter(char arr[]) {
arr = "Changed";
}
int main() {
char test_arr[] = "Testing";
arr_alter(test_arr);
printf("%s\n", test_arr);
return 0;
}
In short, why is function #1 treating the arguments as pointers while function #2 is not?
I'm a bit confused, all help would be greatly appreciated.
Arrays are passed as pointers, by value.
You can take
void copy(char to[], char from[])
as equivalent to
void copy(char * to, char * from)
The difference between the two cases is that the first case dereferences the pointer with the array element operator [].
The second case does not do this, it overwrites the passed pointer. But the pointer was passed by value, so neither the array content nor the passed pointer of the caller change.
First of all the first program has undefined behaviour.
Array foo is defined as having only one element (the terminating zero of the "empty" string literal)
char foo[] = "";
However you are going to copy string "Testing" in the array.
copy(foo, bar);
This results in overwritting the memory that does not belong to array foo.
Array foo should be enough large to be able to accomodate string "Testing".
For example
char foo[8];
According to the C Standard (6.7.6.3 Function declarators (including prototypes))
7 A declaration of a parameter as ‘‘array of type’’ shall be adjusted
to ‘‘qualified pointer to type’’, where the type qualifiers (if any)
are those specified within the [ and ] of the array type
derivation....
On the other (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 this function declaration
void copy(char to[], char from[]);
parameters to and from are adjusted to pointers. So this function declaration is equivalent to the following function declaration
void copy(char *to, char *from);
and the both declare the same one function.
You may write in the program the both declarations. For example
#include <stdio.h>
void copy(char to[], char from[]);
void copy(char *to, char *from);
void copy(char to[], char from[]) {
int i = 0;
while ((to[i] = from[i]) != '\0') i++;
}
//...
but the definition of the function shall be only one.
And in this function call
copy(foo, bar);
according to the second quote from the Standard arrays foo and bar are converted to pointers to their first elements.
As for the function from the second program then function parameters are its local variables. A function deals with copies of its arguments. So any changes of a copy of an argument do not influence on the argument itself.
You can imagine the definition of function arr_alter and its call the following way
arr_alter(test_arr);
//...
void arr_alter( /*char arr[] */) {
char *arr = test_arr;
arr = "Changed";
}
After exiting the function its local variable arr will be destroyed. Variable test_arr will not be changed and moreover arrays have no the assignment operator. You can not reassign an array such a way.
char to[] and char from[] is the equivalent to assigning a char ptr to the first element of the array.
Say you had char s[10]= "hello";
print(s);
Is the same as
print(&s[0]);
The address of the first slot in the array.
Basically I have an array of words
void print(char *str) {
cout << str <<endl;
}
int main() {
int i =0;
char* name[] = {"Fred", "John", "Jimmy"};
print(*name[0]);
}
I would like to pass only first word to a function, but when I am doing in a way as I am doing right now it passes all the names.
You have an extra dereference there, the code should be like this:
print(name[0]);
Ideally, your print function should take const char*, because it does not modify the strings passed in.
char* name[] is an array of pointers to char, typically strings.
void print(char *str) requires a single pointer to a char as an argument.
By calling print(*name[0]), you are actually taking the first pointer from your name[] array, and dereferencing it to turn it into a single char. Since your function requires a pointer to char, you simply need to call it with print(name[0]) and you'll get the first item in your array.
Suppose I have an array of pointers to char in C:
char *data[5] = { "boda", "cydo", "washington", "dc", "obama" };
And I wish to sort this array using qsort:
qsort(data, 5, sizeof(char *), compare_function);
I am unable to come up with the compare function. For some reason this doesn't work:
int compare_function(const void *name1, const void *name2)
{
const char *name1_ = (const char *)name1;
const char *name2_ = (const char *)name2;
return strcmp(name1_, name2_);
}
I did a lot of searching and found that I had to use ** inside of qsort:
int compare_function(const void *name1, const void *name2)
{
const char *name1_ = *(const char **)name1;
const char *name2_ = *(const char **)name2;
return strcmp(name1_, name2_);
}
And this works.
Can anyone explain the use of *(const char **)name1 in this function? I don't understand it at all. Why the double pointer? Why didn't my original function work?
Thanks, Boda Cydo.
If it helps keep things straight in your head, the type that you should cast the pointers to in your comparator is the same as the original type of the data pointer you pass into qsort (that the qsort docs call base). But for qsort to be generic, it just handles everything as void*, regardless of what it "really" is.
So, if you're sorting an array of ints, then you will pass in an int* (converted to void*). qsort will give you back two void* pointers to the comparator, which you convert to int*, and dereference to get the int values that you actually compare.
Now replace int with char*:
if you're sorting an array of char*, then you will pass in a char** (converted to void*). qsort will give you back two void* pointers to the comparator, which you convert to char**, and dereference to get the char* values you actually compare.
In your example, because you're using an array, the char** that you pass in is the result of the array of char* "decaying" to a pointer to its first element. Since the first element is a char*, a pointer to it is a char**.
Imagine your data was double data[5] .
Your compare method would receive pointers (double*, passed as void*) to the elements (double).
Now replace double with char* again.
qsort is general enough to sort arrays consisting of other things than pointers. That's why the size parameter is there. It cannot pass the array elements to the comparison function directly, as it does not know at compile time how large they are. Therefore it passes pointers. In your case you get pointers to char *, char **.
The comparison function takes pointers to the type of object that's in the array you want to sort. Since the array contains char *, your comparison function takes pointers to char *, aka char **.
Maybe it is easier to give you an code example from me. I am trying to sort an array of TreeNodes and the first few lines of my comparator looks like:
int compareTreeNode(const void* tt1, const void* tt2) {
const TreeNode *t1, *t2;
t1=*(const TreeNode**)tt1;
t2=*(const TreeNode**)tt2;
After that you do your comparison using t1 and t2.
from man qsort:
The contents of the array are sorted in ascending
order according to a comparison function pointed to by
compar, which is called with two arguments that **point**
to the objects being compared.
So it sounds like the comparison function gets pointers to the array elements. Now a pointer to a char * is a char **
(i.e. a pointer to a pointer to a character).
char *data[5] = { "boda", "cydo", "washington", "dc", "obama" };
is a statement asking the compiler for an array of size 5 of character pointers. You have initialized those pointers to string literals, but to the compiler, it's still an array of five pointers.
When you pass that array into qsort, the array of pointers decays into a pointer pointing to the first element, in accordance with C array parameter passing rules.
Therefore you must process one level of indirection before you can get to the actual character arrays containing the constants.
#bodacydo here is a program that may explain what other programmers are trying to convey but this would be in context of "integers"
#include <stdio.h>
int main()
{
int i , j;
int *x[2] = {&i, &j};
i = 10; j = 20;
printf("in main() address of i = %p, address of j = %p \r\n", &i, &j);
fun(x);
fun(x + 1);
return 0;
}
void fun(int **ptr)
{
printf("value(it would be an address) of decayed element received = %p, double dereferenced value is %d \r\n",*ptr, **ptr);
printf("the decayed value can also be printed as *(int **)ptr = %p \r\n", *(int **)ptr );
}
qsort() passes a pointer to the user-defined comparison function and as you have a char * (pointer to char array) hence your comparison function should dereference from pointer to pointer hence char **.