I was exploring typedefs and stumbled upon this program
EDIT: Nearly all the answers were concerned about the warnings it generates. So, I went ahead and removed all the warnings but the question remains the same.
#include<stdio.h>
typedef int int3[3];
int main(){
int a[2][3] = {{1,2,3}, {4,5}};
int3 *p = a;
int *ip = (int *) a;
printf("sizeof:\np: %lu\n(*p+0): %lu\n**p: %lu\nip: %lu\n*ip: %lu\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
printf("---\n");
printf("p: %p\tp+1: %p\n*p: %p\t*p+1: %p\n**p: %d\nip: %p\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
return 0;
}
on one run it shows:
sizeof:
p: 8
(*p+0): 8
**p: 4
ip: 8
*ip: 4
---
p: 0x7ffe36df31b0 p+1: 0x7ffe36df31bc
*p: 0x7ffe36df31b0 *p+1: 0x7ffe36df31b4
**p: 1
ip: 0x7ffe36df31b0
*ip: 1
My question is:
If p and *p are equal
and **p = 1
then why not *p = 1 as well ?
Provided size of pointer = 8 and size of int = 4
Even if taking in account pointer arithmetic, then *p should at least be 0xkk kk kk kk 00 00 00 01
k being any hex number (consider little-endian)
because de-referencing the same address as int should give 1
EDIT:
To make things clearer, consider this table:
+-----------+----------------------+------------------+
|Variable | Value | Address |
| | | |
| | | |
| p | 0x7ffe36df31b0 | |
| | | |
|*p | 0x7ffe36df31b0 | 0x7ffe36df31b0 |
| | | |
|**p | 1 | 0x7ffe36df31b0 |
+-----------+----------------------+------------------+
How can *p and **p have same address but different value ?
First, note that this code in a confusing mish-mash of constraint violations combined with array decay to generate output of questionable usefulness. But I'll try to answer your question as to what's going on, and try using mundane explanations without resorting to citations from the C Standard, as others already have answered in that manner.
How can *p and **p have same address but different value ?
Because p is a pointer to an array.
Given
typedef int int3[3];
int3 *p;
that means *p is a three-dimensional array. Note that
int3 *p = a;
is a constraint violation, as noted elsewhere. You can force that to "work" with a cast, but it's still fundamentally wrong and the code only "gets away" with it because the address of an array is the address of the first element of that array - and your current implementation doesn't differentiate the pointer types in a significant-enough fashion they they're fundamentally incompatible. Pick an implementation where a plain int * is, say, a 32-bit offset value while an array would have as its address both a 32-bit segment and a 32-bit offset value, and the code would likely generate nonsense if it didn't fail utterly. That's why the C Standard requires pointers to be to "compatible types" - because pointers don't have to be compatible at all.
That problem aside, the initialization/assignment on your implementation can seemingly be treated as
int3 *p = ( int3 * ) a;
Since that "works", that means p contains the address of a three-element array of int values. So dereferencing p with *p is the same as a[0], or the first three-element int array in the two-dimensional a array.
So what is *p, then?
It's exactly the same in this case as a[0], an array. And such a bare array reference decays to an address*, and that address is of the same type as a pointer to an element of the array. And the value of that address will be that of the address of the first element of the array.
So *p, which is a three-element array of int, can itself be dereferenced and evaluate to the first element of a[0], or a[0][0]. So **p is the same as a[0][0].
And a[0][0] - or **p - is an int that is initialized with the value of 1.
While *p is a[0] and the address of that first element.
* - A lot of people say an array "decays to a pointer" or "an array is a pointer", but I like "decays to an address" because a pointer can be assigned to but an address simply is - it can't be assigned to itself, just like an array itself can't be assigned to, but the address can be assigned to something else, like a pointer. Note than when an array is passed to a function, the address of the array actually is passed as an actual pointer. The pointer is the function's parameter and that function parameter can be assigned to...
the posted code, when compiled with:
gcc -c -Wall -Wextra -Wconversion -pedantic -std=gnu11
results in the following compiler messages:
gcc -ggdb -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c "untitled.c" (in directory: /home/richard/Documents/forum)
untitled.c: In function ‘main’:
untitled.c:6:15: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
int *ip = a;
^
untitled.c:7:26: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
~^
%ld
untitled.c:7:38: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘long unsigned int’ [-Wformat=]
printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
~^
%ld
untitled.c:7:47: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘long unsigned int’ [-Wformat=]
printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
~^
%ld
untitled.c:7:55: warning: format ‘%d’ expects argument of type ‘int’, but argument 5 has type ‘long unsigned int’ [-Wformat=]
printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
~^
%ld
untitled.c:7:64: warning: format ‘%d’ expects argument of type ‘int’, but argument 6 has type ‘long unsigned int’ [-Wformat=]
printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
~^
%ld
untitled.c:9:17: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int (*)[3]’ [-Wformat=]
printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
~^
untitled.c:9:26: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘int (*)[3]’ [-Wformat=]
printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
~^ ~~~
untitled.c:9:34: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 4 has type ‘int *’ [-Wformat=]
printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
~^
%ls
untitled.c:9:44: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 5 has type ‘int *’ [-Wformat=]
printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
~^ ~~~~
%ls
untitled.c:9:61: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 7 has type ‘int *’ [-Wformat=]
printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
~^
%ls
Compilation finished successfully.
The compiler finishes up by saying the compilation was successful. That does NOT mean that it is ok to run this code and expect valid results/output.
When you correct the code so it cleanly compiles, then please post a EDIT to your question that contains the modified/corrected code.
gcc -ggdb -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c "untitled.c" (in directory: /home/richard/Documents/forum)
untitled.c: In function ‘main’:
untitled.c:6:15: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
int *ip = a;
^
untitled.c:7:26: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
~^
%ld
untitled.c:7:38: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘long unsigned int’ [-Wformat=]
printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
~^
%ld
untitled.c:7:47: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘long unsigned int’ [-Wformat=]
printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
~^
%ld
untitled.c:7:55: warning: format ‘%d’ expects argument of type ‘int’, but argument 5 has type ‘long unsigned int’ [-Wformat=]
printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
~^
%ld
untitled.c:7:64: warning: format ‘%d’ expects argument of type ‘int’, but argument 6 has type ‘long unsigned int’ [-Wformat=]
printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
~^
%ld
untitled.c:9:17: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int (*)[3]’ [-Wformat=]
printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
~^
untitled.c:9:26: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘int (*)[3]’ [-Wformat=]
printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
~^ ~~~
untitled.c:9:34: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 4 has type ‘int *’ [-Wformat=]
printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
~^
%ls
untitled.c:9:44: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 5 has type ‘int *’ [-Wformat=]
printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
~^ ~~~~
%ls
untitled.c:9:61: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 7 has type ‘int *’ [-Wformat=]
printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
~^
%ls
Compilation finished successfully.
What you have here is constraint violation because you are using incompatible pointer types in the following initialization:
int *ip = a;
As per C11 standard section on Pointer declarators
For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.
and on Simple assignment/Constraints
the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;
The compiler is require to emit a diagnostic in this case which it does:
<source>:8:15: warning: initialization of 'int *' from incompatible pointer type 'int (*)[3]' [-Wincompatible-pointer-types]
int *ip = a;
See Demo
When you compile a program, it is good practice to enable all warnings and treat warnings as errors so as to avoid (as far as possible) this kind of behavior.
I want to use Netgen - a generator for capacitated networks. But I've got two problems:
If I run make then I get the following error:
cc -O -DDIMACS -c -o netgen.o netgen.c
In file included from netgen.c:86:0:
netgen.h:45:6: error: conflicting types for ‘random’
long random(long, long); /* generate random integer in interval */
^
In file included from netgen.h:31:0,
from netgen.c:86:
/usr/include/stdlib.h:321:17: note: previous declaration of ‘random’ was here
extern long int random (void) __THROW;
^
netgen.c: In function ‘main’:
netgen.c:522:11: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 2 has type ‘int’ [-Wformat=]
printf("n %ld\n", i + 1);
^
netgen.c:535:11: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 2 has type ‘int’ [-Wformat=]
printf("n %ld s\n", i + 1);
^
netgen.c:538:11: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 2 has type ‘int’ [-Wformat=]
printf("n %ld t\n", i + 1);
^
netgen.c:550:11: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 2 has type ‘int’ [-Wformat=]
printf("n %ld %ld\n", i + 1, B[i]);
^
netgen.c:553:9: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 4 has type ‘int’ [-Wformat=]
printf("a %ld %ld %ld %ld %ld\n", FROM[i], TO[i], 0, U[i], C[i]);
^
<builtin>: recipe for target 'netgen.o' failed
make: *** [netgen.o] Error 1
I know the conflict is a result of using stdlib.h and random.c - how can I fix this?
The second problem is that I don't know how to use the problem sets (for example problems.8 and problems.40 (see link above))
Thank you in advance!
I have absolutely no idea why it returns 2 for a=2 and b=2..
Any ideas?
#include <stdlib.h>
int main()
{
double a,b,c;
printf("a=");
scanf("%d", &a);
printf("b=");
scanf("%d", &b);
printf("c=");
scanf("%d", &c);
printf("x=%d", a+b);
return 0;
}
The specifier "%d" expects an integer and you are passing the address of a double. Using the wrong specifiers in scanf leads to undefined behavior.
Also, using the wrong specifier in printf is the same thing. Because printf takes a variable number of arguments a + b which is a double can't be converted to an integer.
%d is for reading integers, use %f or %lf for float/double.
printf should use something like %f instead of %d. The same for scanf.
If you want to accept a float input, use scanf (and printf) with the %lf formatting character, not %d (which is for integers).
The behavior of your current program is undefined, since the scanf calls are writing an integer to a float variable. Also, you're missing include <stdio.h> at the top of your program. To catch errors like these, turn on the warnings in your C compiler:
$ gcc so-scanf.c -Wall
so-scanf.c: In function ‘main’:
so-scanf.c:6:5: warning: implicit declaration of function ‘printf’ [-Wimplicit-function-declaration]
so-scanf.c:6:5: warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]
so-scanf.c:7:5: warning: implicit declaration of function ‘scanf’ [-Wimplicit-function-declaration]
so-scanf.c:7:5: warning: incompatible implicit declaration of built-in function ‘scanf’ [enabled by default]
so-scanf.c:7:5: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘double *’ [-Wformat]
so-scanf.c:9:5: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘double *’ [-Wformat]
so-scanf.c:11:5: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘double *’ [-Wformat]
so-scanf.c:13:5: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘double’ [-Wformat]
I'm curious why GCC shows me two identical warnings when compiling this file:
$ cat test.c
#include <stdio.h>
int main (int argc, char const *argv[])
{
long foo = 0l;
printf("%i\n", foo);
return 0;
}
$ gcc-4.2 -Wall test.c
test.c: In function ‘main’:
test.c:6: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘long int’
test.c:6: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘long int’
Interestingly, Clang also gives two warnings:
$ clang test.c
test.c:6:14: warning: conversion specifies type 'int' but the argument has type 'long' [-Wformat]
printf("%i\n", foo);
~^ ~~~
%ld
test.c:6:14: warning: conversion specifies type 'int' but the argument has type 'long' [-Wformat]
printf("%i\n", foo);
~^ ~~~
%ld
2 warnings generated.
Any ideas?
For info:
$ gcc-4.2 -v
Using built-in specs.
Target: i686-apple-darwin11
Configured with: /private/var/tmp/gcc/gcc-5666.3~278/src/configure
--disable-checking --enable-werror --prefix=/usr --mandir=/share/man
--enable-languages=c,objc,c++,obj-c++
--program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib
--build=i686-apple-darwin11 --program-prefix=i686-apple-darwin11-
--host=x86_64-apple-darwin11 --target=i686-apple-darwin11
--with-gxx-include-dir=/include/c++/4.2.1
Thread model: posix
gcc version 4.2.1 (Apple Inc. build 5666) (dot 3)
$ clang -v
Apple clang version 2.1 (tags/Apple/clang-163.7.1) (based on LLVM 3.0svn)
Target: x86_64-apple-darwin11.1.0
Thread model: posix
EDIT: the 'multi-architecture' hypothesis a few have suggested sounded good, but I'm not sure it's right. If I force a single architecture with -arch, I get two warnings. If I specify -arch x86_64 -arch i386, I get two sets of duplicate warnings!
$ gcc-4.2 -Wall -arch x86_64 test.c
test.c: In function ‘main’:
test.c:6: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘long int’
test.c:6: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘long int’
$ gcc-4.2 -Wall -arch x86_64 -arch i386 test.c
test.c: In function ‘main’:
test.c:6: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘long int’
test.c:6: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘long int’
test.c: In function ‘main’:
test.c:6: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘long int’
test.c:6: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘long int’
EDIT: I don't get dupes for all warning types. -Wformat is the only one I've come across so far. For example, if I throw in an unused variable I only get one warning for that:
$ cat test.c
#include <stdio.h>
int main (int argc, char const *argv[])
{
long foo = 0l;
long bar;
printf("%i\n", foo);
return 0;
}
$ gcc-4.2 -Wall test.c
test.c: In function ‘main’:
test.c:7: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘long int’
test.c:7: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘long int’
test.c:6: warning: unused variable ‘bar’
This is because Apple's stdio.h header attaches a GCC format attribute to its declaration of printf()...
(e.g. see the declaration of printf() here and the declaration of the __printflike() macro here)
...but GCC (and Clang, due to it trying to be very GCC-compatible!) already has built-in knowledge that printf() is a function which takes printf-style arguments. You're getting one warning due to the built-in knowledge, and a second warning due to the explicit attribute.
You can demonstrate the same behaviour on other platforms (with at least several versions of GCC) by doing the same thing yourself:
extern int printf(const char *, ...) __attribute__((__format__ (__printf__, 1, 2)));
int main (int argc, char const *argv[])
{
long foo = 0l;
printf("%i\n", foo);
return 0;
}
If you're targetting two CPU architectures (ARMv6/ARMv7 on iOS, for instance, or i386/x86_64 on Mac), you'll see two copies of each warning because the compiler runs twice for each file (once for each architecture.)
On a Mac, you can get it up to 4 warnings per line if you enable PPC/PPC64 support. ;)
Edit: Matthew's got it spot-on in the accepted answer.
It looks like you're compiling for iOS. The code is being compiled multiple times for multiple architectures. The warning is being generating for each architecture.