funny type error in C - c

I'm writing a program in C, which I am a complete beginner in, to find prime numbers. The problem I have is that when I initialize a variable to the int type like this...
int num;
and then stuff happens
blah blah blah
but nothing happens to num, it's kept in reserve and only used to modify other variables.
and then when I try
printf("%d",&num);
and compile it with gcc it gives me this error
warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’ [-Wformat]
but it seems really silly, whats the difference between int and int *? and how can I print num if it isn't a num?
please help I'm so confused.

& takes the address of num. Use
printf("%d\n",num);

First, it´s only a warning (a good one, but you can run the program nonetheless).
If you do that, you´ll see some strange number,
because you´re printing the memory address of your variable.
Remove the & to print the value (and to get rid of the warning too)
You´re probably thinking of scanf, there you need the &
(explanations at this point would be too long, wait until you´re familiar with pointers)

Just to extrapolate a little bit... the difference between int and int* is that int* is a pointer to an int. That means it doesn't actually hold an int value, it holds the address to an int value.

Related

confused by pointer and local variable in C

according to what i learned about function variables they should not 'live' outside their function scope,thus returning a local function variable should cause an error, i do get compiling warnings that i do expect, but it makes no sense to me because the program do work and i am little confused
i wrote the following program:
int * test(int x) {
int f=x+1;
return f; //- int to pointer conversion,idk why this works
}
int main () {
int x = 10;
printf("%d\n",test(x));
}
I first expected the program to crash because we make conversion from int type to pointer at function return, but apparently the program prints 11 which i did not expect, i know this is really bad to write like this anyways it was just a coincidence i wrote something like this and it worked and I had alot of questions after that
the warnings i expected to get :
Solution.c: In function ‘test’:
Solution.c:10:12: warning: return makes pointer from integer without a cast [-Wint-conversion]
return f;
^
Solution.c: In function ‘main’:
Solution.c:15:14: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’ [-Wformat=]
printf("%d\n",test(x));
~^ ~~~~~~~
%ls
can anyone explain how this program works ?
You tell the compiler that function test() should return return a pointer to an integer. You don't. You return a value of an integer.
The compiler says, "You're probably doing unintentional stuff here, just sayin'. I'll cast this integer to a pointer for you."
Then the compiler says, "You want to print the value of an integer here but what you're giving is a pointer. Just sayin'. I'll cast this pointer to an integer for you."

How does assigning a string to int and passing that int to printf prints the string properly?

Why does this work? (i.e how is passing int to printf() results in printing the string)
#include<stdio.h>
int main() {
int n="String";
printf("%s",n);
return 0;
}
warning: initialization makes integer from pointer without a cast [enabled by default]
int n="String";
warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
printf("%s",n);
Output:String
compiler:gcc 4.8.5
In your code,
int n="String"; //conversion of pointer to integer
is highly-implementation dependent note 1
and
printf("%s",n); //passing incompatible type of argument
invokes undefined behavior. note 2
Don't do that.
Moral of the story: The warnings are there for a reason, pay heed to them.
Note 1:
Quoting C11, chapter §6.3.2.3
Any pointer type may be converted to an integer type. Except as previously specified, the
result is implementation-defined. If the result cannot be represented in the integer type,
the behavior is undefined. [....]
Note 2:
chapter §7.21.6.1
[....] If any argument is
not the correct type for the corresponding conversion specification, the behavior is
undefined.
and for the type of argument for %s format specifier with printf()
s If no l length modifier is present, the argument shall be a pointer to the initial
element of an array of character type. [...]
The behaviour of your program is undefined.
Essentially, you're assigning a const char* to an int, and the printf converts it back. But do regard that as entirely coincidental: you're not allowed to cast unrelated types like that.
C gives you the ability to shoot yourself in the foot.
int type can store 4 bytes numbers on most today's computers (from -2147483647 to 2147483647)
Which means it ""can"" store SOME address as well, only problem is when your address is bigger than 2147483647 it will cause overflow and you will not be able to get the address, (which is very bad for your program obviously)
An address is a number referring to memory space,
Pointers are made to store addresses, they are larger (8 bytes on 64bits systems, 4 bytes on 32bits systems) and they are also unsigned (only positive)
which means, when you affect int n="String"; if the address to "String" is under 2147483647 it wont cause issues and you code will run (DONT DO THAT)
http://www.tutorialspoint.com/c_standard_library/limits_h.htm
now if you think about it, you can guess why there is a 4GB ram limit on 32bit systems
(sorry about possible english mistakes, I m french)
Compiling with options like -Wall -Wextra -Werror -Wint-to-pointer-cast -pedantic (GCC) will show you very quickly that this behaviour should not be relied upon.

Can int store the base address of string in C?

Why do the code run without error ?
#include <stdio.h>
int main() {
int i="string"; //the base of string can be stored in a character pointer
printf("%s\n",i);
printf("%d",i);
return 0;
}
//compiling on ideone.com language c
OUTPUT:
string
134513984 //some garbage(address of "string")
Please explain if there is some flexibility in the pointer in c. I tried it for c++ which gives error: cannot convert ‘const char*’ to ‘int*’ in initialization
No, you cannot assume this in general. In part, this is because int may not be the same size as char * (in fact, on many 64-bit compilers it will not be the same size).
If you want to store a pointer as an integer, the appropriate type to use is actually intptr_t, from <stdint.h>. This is an integer which is guaranteed to be able to hold a pointer's value.
However, the circumstances when you'd actually want to do this are somewhat rare, and when you do do this you should also include an explicit cast:
intptr_t i=(intptr_t)"string"; //the base of string can be stored in a character pointer
This also complicates printing its value, you'll need to use a macro to be portable:
printf("%"PRIiPTR,i);
To print the original string, you should also cast:
printf("%s", (char *)i);
In general, no: the C standard states that conversions from pointers to integers are implementation defined. Further, this can be problematic on systems where sizeof(char *) and sizeof(int) are different (i.e. x86-64), for two reasons:
int i = "string"; can lose information, if the e.g. 64-bit pointer cannot fit in a 32-bit integer.
printf expects a pointer to be passed in, but gets a smaller integer. It winds up reading some garbage into the full pointer, and can crash your code (or worse).
Often times, however, compilers are "smart" enough to "fix" arguments to printf. Further, you seem to be running on a platform where pointers and integers are the same size, so you got lucky.
If you compiled this program with warnings (which you should) you'd get the following complaints:
main.c:3:9: warning: incompatible pointer to integer conversion initializing 'int' with an expression of type 'char [7]' [-Wint-conversion]
int i="string"; //the base of string can be stored in a character pointer
^ ~~~~~~~~
main.c:4:19: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
printf("%s\n",i);
~~ ^
%d
2 warnings generated.
Warnings generally mean you're doing something that could cause unexpected results.
Most C compilers will let you do this, but that doesn't make it a good idea. Here, the address of the character array "string" gets stored in i. The printf options are determining how the integer is interpreted (as an address or an integer). This can be problematic when char* is not the same size as an int (e.g. on most 64 bit machines).
The C++ compiler is more picky and won't let you compile code like this. C compilers are much more willing, although they will usually generate warnings letting the programmer know it is a bad idea.
Your code is ill-formed in both C and C++. It is illegal to do
int i = "string";
in both languages. In both languages conversion from a pointer to an integer requires an explicit cast.
The only reason your C compiler accepted it is that it was configured by default for rather loose error checking. (A rather typical situation with C compilers.) Tighten up your C compiler settings and it should issue an error for the above initialization. I.e. you can use an explicit conversion
int i = (int) "string";
with implementation-dependent results, but you can't legally do it implicitly.
In any case, the warning your compiler emitted for the above initialization is already a sufficient form of a diagnostic message for this violation.

Why doesn't scanf() treat array and &array the same?

I wrote this simple program
#include <stdio.h>
int main(void)
{
int array[10];
printf("sizeof(array): %lu\n", sizeof(array));
printf("sizeof(&array): %lu\n", sizeof(&array));
printf("array: %p\n", array);
printf("&array: %p\n", &array);
printf("value: ");
scanf("%d", array); // 1
//scanf("%d, &array"); // 2
}
Output:
sizeof(array): 40
sizeof(&array): 8
array: 0x7fffaab6f480
&array: 0x7fffaab6f480
value: 10
It compiles when I use 1. However, it doesn't when I use 2!
I get this compilation warning
warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type
‘int (*)[10]’ [-Wformat=]
scanf("%d", &array);
^
although array and &array have the same value, they have different sizes (40 and 8 respectively) on my system.
On the other hand, this code
int array[10];
fread(&array, x, y, z);
compiles and works perfectly as
int array[10];
fread(array, x, y, z);
I noticed in the warning message that &array has the type int (*)[10]. Now what does that mean?
I also believe I have no troubles with fread() because it accepts a void *, but what about scanf()? How does it differentiate between pointer types?
And why doesn't it treat array as &array even though they're practically have the same value?
Arrays decays to pointers, so using the array as argument is the same as passing a pointer to the first element.
When you're doing &array, you get a pointer to the array (the int (*)[10] thing), and not a pointer to an integer.
With the scanf and printf family, you must pass the exact type that they expect (after the default argument promotions are applied - but that is not relevant in this example).
This is because the arguments correspond to a ... in the prototype, meaning that the compiler does not attempt to convert your argument to the expected type. If you use the wrong type you just get undefined behaviour.
This happens in the second case, scanf("%d", &array). As your examples show &array does not have type int *, therefore the behaviour is undefined.
In practice, it is likely to work anyway if your compiler uses the same representation for int * as it does for int (*)[10], which all modern compilers do AFAIK. But , of course, you should not rely on undefined behaviour, especially when there is an easy fix available.
In the fread example, it matches the prototype parameter void *. Therefore the compiler converts your argument to void *. Since the first element of an array is at the same memory address as the array itself, (void *)&array == (void *)array, even though array and &array have different types (and possibly even different representations), they both point to the same memory address.
First, your program was compiled very well - warning is not an error.
The warning message tells you that there's mismatch between format and type: "%d" format requires int *, but you sent &array, whose type is int (*)[10].
array is 10-length array of int. Its type is int [10]. However, array can be converted to pointer, that is, &array[0].
When you try to pass array to function, you actually pass a pointer, &array[0]. So both this code
printf("%d", array);
scanf("%d", array);
and this another code
printf("%d", &array[0]);
scanf("%d", &array[0]);
are the same.
Now let's look at another thing, &array. Its type is int (*)[10], that is, pointer to array.
Of course, the actual values of both &array[0] and &array are the same, but they have different types. So they're diferent things, as 'A' and 65 are different.
Altough it looks okay since the values are the same, I don't think it is such a good practice - Use array or &array[0].
Both are syntactically correct C, and do exactly the same thing, as you suggest. However, one is more correct than the other. That said, neither is perfect.
To be properly pedantic, you should have this:
scanf("%d", &array[0]);
.. because that's a pointer to an integer, array[0], and what you really want.
In fact, you can pass anything to scanf (if you ignore the documentation), and the compiler is expected to accept it (misuse of the standard library does not trigger an error, traditionally). If you pass something invalid then your program is expected to fail at runtime (or not, if you're lucky -- undefined behaviour is like that).
However, your compiler is trying to be helpful and interpret the scanf format string for you to make sure you did the right thing, but if you look carefully, it's not an error, its a warning. You're free to ignore it, if you choose.
The reason you don't get an error with fread is because that function does not take an integer, it takes void *, and both forms can be converted to that type just as easily.

C programming: '&' with arrays in scanf [duplicate]

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

Resources