This question already has answers here:
With arrays, why is it the case that a[5] == 5[a]?
(20 answers)
String as an array index
(3 answers)
Closed 6 years ago.
This example compiles without warnings/errors (gcc 4.8.2 -Wall):
#include <stdio.h>
int main()
{
char c;
int i;
printf("%p %02x\n",&i,c[&i]);
printf("%p %02x\n",&c,c[&c]);
// important to note that this line DOESN'T compile:
//printf("%p %02x\n",&i,c[i]);
// which makes sense as c is NOT an array, it is a char.
return 1;
}
Why does the syntax c[&i] compile ? Is it intentional or an accident?
Is the syntax c[&i] semantically valid ? (Does it have any useful meaning?)
Example of output for me: (pointers change each time)
0xbfb2577c b7718cea
0xbfb2577b 08
This question originated from a strange bit of code 'ch2[&i]' in question here:
C duplicate character,character by character
NOTE#0 (updated, upon reflection) on duplicates/similar questions:
This question is not a duplicate of the linked questions on c array references. It is related so it is useful to refer to them. The related questions discuss the valid a[b] and b[a] case where one of a or b is a pointer and the other is an int. This question deals with the more weird and maybe should be invalid case where one of a or b is a char.
With C arrays, why is it the case that a[5] == 5[a]? 14 answers
With arrays, why is it the case that a[5] == 5[a]?
String as an array index 3 answers
String as an array index
NOTE #1: This happens with compiler as the type of variable c is char and that can be used as index into array when combined with pointer.
NOTE #2: for some reason, type of c[<ptr>] evaluates to type of <ptr>.
E.g.: the resulting types of c[&pi] and c[&pc] cause warnings in the following code:
int *pi; char *pc; pi=&i; pc=&c;
printf("%p %02x\n",&pi,c[&pi]);
printf("%p %02x\n",&pc,c[&pc]);
Warnings on type 'int *' or 'char *' instead of 'unsigned int':
c/so_cweirdchar2.c: In function ‘main’:
c/so_cweirdchar2.c:13:5: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘int *’ [-Wformat=]
printf("pi %p %02x\n",&pi,c[&pi]);
^
c/so_cweirdchar2.c:14:5: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘char *’ [-Wformat=]
printf("pc %p %02x\n",&pc,c[&pc]);
^
In C, the [] postfix pointer displacing operator is commutative. If a[i] is a valid expression, then so is i[a] and means the same thing. Though we have to watch operator associativity and precedence to make sure we do this reversal right. Your c[&i] means the same thing as (&i)[c]: the pointer &i displaced by the integer c.
The basis for the commutativity of [] is the equivalence between indexing and the combination of pointer displacement and dereferencing, where the + operator is commutative:
E1[E2] <--> *(E1 + E2)
^ ^
| |
v v
E2[E1] <--> *(E2 + E1)
Here we understand E1 to be fully parenthesized expressions, so we are unconcerned about precedence. In effect we are manipulating abstract syntax trees in which E1 and E2 are nodes.
Compiles with no error. Perfectly valid C:
int main (int argc, char** argv)
{
int n=5;
char *a="abcdefghijk";
printf("%c\n", a[n]);
printf("%c\n", n[a]);
return 0;
}
Related
#include<stdio.h>
#include<string.h>
void fun(char** a)
{
strcpy(*a, "ponky" );
}
int main()
{
char a[100] = "pinky";
fun(&a );
printf("\n %s \n", a );
return 0;
}
Copying a string in a function through double pointer.
Why the above program gives segmentation fault?
note: I suspect this question to be a duplicate and I've found many similar questions but I haven't found an exact duplicate. Therefore I post an answer. Should someone find an exact duplicate I'll remove this answer.
Why the above program gives segmentation fault?
The short answer is that you have a type mismatch when calling fun. You don't give fun a "pointer to pointer to char" as it expects. Consequently, it fails big time.
But what do you then pass to fun? And how should you have found out that something was wrong?
The answer is: Set compiler warning level high and consider all warnings to be errors
For gcc that could be:
gcc -xc -Wall -pedantic -Werror main.c
(Other compilers have similar options)
On my system I get:
In function 'main':
error: passing argument 1 of 'fun' from incompatible pointer type [-Werror=incompatible-pointer-types]
13 | fun(&a );
| ^~
| |
| char (*)[100]
note: expected 'char **' but argument is of type 'char (*)[100]'
3 | void fun(char** a)
| ~~~~~~~^
so it's clear that something is wrong and the following line tells it all:
note: expected 'char **' but argument is of type 'char (*)[100]'
you pass char (*)[100] instead of char **
But what is char (*)[100]?
It's a "pointer to an array of char". Since fun uses it as "pointer to pointer to char" you have undefined behavior (which in your case resulted in a seg fault). That is - fun would expect *a to be a "pointer to char" but you passed "pointer to an array of char" so *a is not a "pointer to char".
It's undefined behavior so we can't tell what is going on. However, on many systems it will read the string "pinky" and interpretate it as a pointer to char which will fail big time.
This question already has answers here:
What is the strict aliasing rule?
(11 answers)
Closed 5 years ago.
I put the code directly.
#include <stdio.h>
struct A
{
int a;
int b;
};
int main()
{
struct A test;
double *p = (double *)&(test.a);
*p = 5;
printf("variable a: %d\n", &test.a);
printf("variable b: %d\n", &test.b);
return 0;
}
I run this code in centos7, the compiler is gcc4.8.5.And my computer uses little ending to store.
As you see, the memory of variable b will be overwritten, I expected a is 0x0000 0005 and b is 0x0000 0000.
But the answer is:
variable a: 0
variable b: 1075052544
Why variable a is 0x 0000 0000 and b is 0x4014 0000?
The behaviour of your code is undefined.
You can't dereference p once you've set it to the address of something that is not a double type.
To see what your compiler has done with this input, check the generated assembly.
The behaviour of your code is undefined.
Clang compiler generate warning message:
source_file.c:13:20: warning: format specifies type 'int' but the argument has type 'int *' [-Wformat]
printf("%d\n", &test.a);
~~ ^~~~~~~
source_file.c:14:20: warning: format specifies type 'int' but the argument has type 'int *' [-Wformat]
printf("%d\n", &test.b);
~~ ^~~~~~~
#include <stdio.h>
void main()
{
int a[]={1,2,3,4};
printf("%u %u ",a ,&a); //a
printf("%d %d ", *a ,*&a); //b
}
In ath line the output of a and &a are same address but in bth line *&a does not give me the answer as 1.
I know that &a means pointer to array of integers but as the address is same, it should print 1 right?
a decays to the pointer to the first element of the array.
&a is the pointer to the array of 4 ints.
Even though the numerical values of the two pointers are the same, the pointers are not of the same type.
Type of a (after it decays to a pointer) is int*.
Type of &a is a pointer to an array of 4 ints - int (*)[4].
Type of *a is an int.
Type of *&a is an array of 4 ints - int [4], which decays to the pointer to the first element in your expression.
The call
printf("%d %d ", *a ,*&a);
is equivalent to:
printf("%d %d ", *a , a);
BTW, You should use %p for pointers. Otherwise, you invoke undefined behavior. Increase the warning level of your compiler to avoid making such errors.
Taking a simpler version of your code as follows:
#include <stdio.h>
void main()
{
int a[]={1,2,3,4};
printf("%d %d ", *a ,*&a); //b
}
If I compile that code I get this warnings:
test1.c
D:\Temp\test1.c(7): warning C4477:
'printf' : format string '%d' requires an argument of type 'int', but variadic
argument 2 has type 'int *'
Microsoft (R) Incremental Linker Version 14.00.23506.0
Copyright (C) Microsoft Corporation. All rights reserved.
That warning message gives you the reason why this is not working as you expect.
Now I can change that code to remove those warnings and I end up with code like this:
#include <stdio.h>
void main()
{
int a[]={1,2,3,4};
int (*p)[4] = &a;
printf("\n%u %u ", *a ,*p[0]); //b
}
That code clean compiles and when it is run you get the expected output:
1 1
The latest draft of the C standard suggests that
If the operand is the result of a unary * operator,
neither that operator nor the & operator is evaluated and the result is as if both were omitted...
However, the above paragraph refers to the case when it's &*, not *&. Try to think of it this way:
&a // pointer to array[4] of integers
*(&a) // array[4] of integers
------------------------------------------
a // array[4] of integers
Note that the operator * removes single layer of pointers. Therefore, *(&a) is identical to a semantically. In this case, a is converted to an expression with the type pointer to an integer, because another paragraph suggests that
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...
In conclusion, the fact that the address of a (not the element inside) is printed is natural.
Please do one more thing in your code:
printf("%u %u ",a+1 ,&a+1); //a1
This question already has answers here:
format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[64]
(3 answers)
Closed 9 years ago.
I got a warning in my program, and it says:
format '%c' expects argument of type 'char *' , but argument 2 has type 'char (*)[10]' [-Wformat]
Here's my program:
#include<stdio.h>
int main()
{
char array[10];
scanf("%10c", &array);
printf("%.10s", array);
return 0;
}
The warning disappears when I remove '&' from scanf.
I know, it's an array and doesn't require &. But don't they have same effect?
I mean both '&array' and 'array' give address of its first element, right?
If so, what's the difference here?
I read some related questions here, and googled a lot.
It has been said that '&array' is a pointer to an array of characters if 'array' is an array while 'array' itself is a pointer to char.
According to what it says, since I'm using %c, a pointer to an array of characters should be passed, I think.
Idk, I would very greatful if someone explains how %[width]c works.
I also verified that all 'array', '&array' and '&array[0]' give address of its first element.
Here's what I did:
int main()
{
char array[10];
puts("ADDRESS:");
printf(" %p \n %p \n %p", array, &array, &array[0]);
return 0;
}
If they all give same address, why is it giving such warnings?
It also works for %s.
They all work fine in most of windows compiler, without any warnings.
Since I'm a windows user, I never used gcc compiler before. And what I was thinking was it's just not mandatory to write & as with function pointers.
You don't necessarily have to write & with function pointers, I read.
I'm getting more and more confused, please help me get it.
Thank you.
array and &array both yield a pointer to the same address, but with different types. The former is equivalent in most situations to &array[0], a char * in your case. &array, however, is the address of the array itself, which has type char (*)[10] in your example.
array and &array are not the same... even if they have same address location in it.
array here being char array, it points to a single char, and if you increment it increases by 1 char size.
but &array points to the entire array and if increments it increases by the array size.
scanf function expects for the array.. not &array
This question already has answers here:
What Does Adding One to a Character Array in C Do?
(4 answers)
Closed 9 years ago.
If I have a pointer to a pointer like the variable 'bs' in this sample:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
char **bs = {"this", "is", "a", "test"};
puts(bs);
return 0;
}
the puts statement shows 'this' on the screen. How would I go about getting it to show 'is' and so forth. I though I could just do something like:
puts(bs+1);
What does adding a number to a pointer variable actually do? Does it point to the next address, or does it take the type of the pointer into consideration and uses the size of the variable it is pointing to to determine where the next variable starts in memory?
the puts statement shows 'this' on the screen.
That's just (bad) luck, the code invokes undefined behavior, if the compiler doesn't refuse to compile it at all.
The warnings produced by clang (by default) for the code are
$ clang badpoint.c
badpoint.c:6:18: warning: incompatible pointer types initializing 'char **' with an
expression of type 'char [5]' [-Wincompatible-pointer-types]
char **bs = {"this", "is", "a", "test"};
^~~~~~
badpoint.c:6:26: warning: excess elements in scalar initializer
char **bs = {"this", "is", "a", "test"};
^~~~
badpoint.c:8:10: warning: incompatible pointer types passing 'char **' to parameter of
type 'const char *'dereference with * [-Wincompatible-pointer-types]
puts(bs);
^~
*
/usr/include/stdio.h:688:32: note: passing argument to parameter '__s' here
extern int puts (__const char *__s);
^
3 warnings generated.
gcc generates a warning for each excess initializer, while clang gives only one for the first of the three, otherwise the warnings from gcc (also by default) are a bit less informative, but the same.
So what's going on?
You are trying to initialize a scalar (char**), and provide {"this", "is", "a", "test"}, a brace-enclosed initializer-list containing four _initializer_s. Per 6.7.9 (11)
The initializer for a scalar shall be a single expression, optionally enclosed in braces. The initial value of the object is that of the expression (after conversion); the same type constraints and conversions as for simple assignment apply, taking the type of the scalar to be the unqualified version of its declared type.
That violates a "shall" requirement, and hence invokes undefined behavior.
If the compiler does not terminate the translation there, it probably just ignores the excess initializers - clang and gcc both do - and treats the declaration as if it was
char **bs = "this";
Which causes the warning about initialization from an incompatible type, since that tries to initialize a char** with a char[5], but per 6.5.16.1 the type of the initializer must be compatible with char**.
Nevertheless, if the compiler successfully translates the program, it is likely to result in bs containing the address of the first char in the string literal (the array "this" is converted to a pointer to its first element on the right hand side of an assignment operator).
Then the call
puts(bs)
Passes a pointer of the wrong type (char**) to puts, which is a constraint violation and requires a diagnostic message from the compiler (and makes the program invalid).
But the pointer happens to contain the correct address, and the undefined behavior manifests as the program printing "this".
How would I go about getting it to show 'is' and so forth
By correcting the program. As is, the strings "is", "a", and "test" do not even appear in the object file produced by gcc or clang.
One way to correct it would be changing the declaration to
char *bs[] = {"this", "is", "a", "test"};
So that bs is an array of four char*, pointing to the (respective first elements of the) four strings.
Then you have to adjust the call to puts, dereferencing or subscripting bs,
puts(bs[0]);
To print "this";
for(int i = 0; i < 4; ++i) {
puts(bs[i]);
}
To print all four strings on separate lines.