Unexpected result when parsing argument in main function in C - c

I have really simple code to understand command line arguments parsing of main in C language:
#include <stdio.h>
int main(int argc, char* argv[]){
for(int i=1; i < argc; i++)
printf("%d\n", argv[i]);
printf("Number of arguments: %d\n", argc);
}
Having compiled and executed in a terminal passing 3 integers (eg. 1, 2, 3), I obtain the following strange result:
1175842993
1175842995
1175842997
Number of arguments: 4
I know that the solution is lying right straightforwardly towards my eyes, but it's been a hour that I cannot actual figure it out! Any hints? Thanks!

Dereference your pointer:
printf("%d\n", *argv[i]);
You may also be a little surprised, as you will get a numerical value represented by the (first) character printed; for instance for 1 it is 49.
In general you can tell your compiler to tell you a bit more by enabling more warnings. For instance gcc -Wall would tell you:
warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘char *’ [-Wformat=]
printf("%d\n", argv[i]);
Which would actually be a pretty solid hint.
And a side note: if you declare your main as int, you should return one too. ;) (But see EDIT2 for details).
EDIT: I guess I should have mentioned that with the actual output surprise in the second paragraph.
If verbatim reprint of the argument(s) is what you actually wanted. You'd use %s in your formatting string as Jonathan Leffler pointed out in the comment. In that case, you want the argument passed to be pointer to a string again (i.e. you do not use the * dereference operator).
EDIT2: As pointed out by Antti Haapala regarding the closing "Side note".
When using C99 or C11 you do not have to explicitly return (a value) for your main (and we're talking about main) that has been declared to return int. In that case default of 0 will be assumed. You really only need to do that for when adhering to C89 standard or other functions. For sake of simplicity though and/or when not sure what your target compiler configuration is, you won't be wrong being (type) consistent between your declared and actually returned value type. And again. gcc -Wall for example would let you know about that.

Related

I wanted to know about the working of "printf" function in c. For example for the print statements used in below code the outputs are different why?

how come the pointer gets printed even with %d
int main()
{
int s=5 ,t ,**p ,*n;
n=&s;
p=&n;
printf("%d",n);
printf("\n%p",*p);
return 0;
}
//answer for first print statement is purely integers
//answer for second one is hexadecimal
This is undefined behavor. You must match the type required by the format specifier to the type of the value passed.
In a comment you made it clear that you wanted to know "why it didn't show any kind of warning or anything".
printf is an example -- the best-known example -- of a variadic or "varargs" function. It does not accept one, fixed list of arguments with an exact number of predefined types. Every time you call printf, you call it with a different number of arguments, and the only way to determine how many arguments and what types they should be is to go through the format string looking for the % signs.
The printf function itself knows how to do this. At run time, when you call it, it goes through the format string looking for % signs, and each time it finds one, it looks at the following letter to determine what type of argument it should fetch next. But at run time, there's no mechanism to double-check what type of argument has actually been passed -- printf just blindly fetches a value (typically from the stack) that's assumed to be of the correct type, and prints it out assuming it had the correct type.
But that was at run time. The only way you could get a warning or error message at compile time would be for the compiler to go through the format string looking for % signs, and match them up with the actual arguments it can see you're passing.
Once upon a time, that wasn't a reasonable thing for a compiler to do. But times have changed, and today this is actually something that a good compiler does do! Here's what I got when I compiled your code using clang on my Mac:
warning: format specifies type 'int' but the argument has type 'int *'
And here's what I got when I compiled it with gcc, using the -Wall option:
warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’
warning: unused variable ‘t’
So, the bottom line is: use a modern compiler (and remember to request warnings), and it should tell you about problems like these.
P.S. In a comment I said, "%p is for pointers, but you gave it an int." But I misread your code. Your first printf call uses %d, and passes n, but n is int * which is a pointer, so that's wrong.
Your second printf call uses %p, and passes *p. In your code, p is an int **, a pointer to pointer to int, so *p is a pointer-to-int, and that call is therefore (mostly) correct.

%s expects 'char *', but argument is 'char[100]'

I have something along the lines of:
#include <stdio.h>
typedef struct {
char s[100];
} literal;
literal foo()
{
return (literal) {"foo"};
}
int main(int argc, char **argv) {
printf("%s", foo().s);
return 0;
}
And I get this error when compiling it (with gcc):
warning: format ‘%s’ expects argument of type ‘char *’, but argument 2
has type ‘char[100]’ [-Wformat=]
any1 has any ideas on how I can fix it? And what is wrong with that function return type?
EDIT
The problem (if not clear in the discussion) was the c standard gcc was using to compile the file. if you use -std=c99 or -std=c11 it works.
It is not an error but a warning, not all warnings that -Wall produces are sensible.
Here the compiler is "kind-of" right: before evaluation your argument is an array and not a pointer, and taking the address of a temporary object is a bit dangerous. I managed to get rid of the warning by using the pointer explicitly
printf("%s\n", &foo().s[0]);
Also you should notice that you are using a rare animal, namely an object of temporary lifetime, the return value or your function. Only since C99, there is a special rule that allows to take the address of such a beast, but this is a corner case of the C language, and you would probably be better off by using some simpler construct. The lifetime of the pointer ends with the end of the expression. So if you would try to assign the pointer to a variable, say, and use it later on in another expression, you would have undefined behavior.
Edit(s): As remarked by mafso in a comment, with C versions from before C99, it was not allowed to take the address of the return value of the function. As Pascal Cuoq notes, the behavior of your code is undefined even for C99, because between the evaluation of the arguments and the actual call of the function there is a sequence point. C11 rectified this by indroducing the object of temporary lifetime that I mentioned above.
I don't exactly why maybe someone with more knowledge in C than me can explain it but writing main() on this way:
int main(int argc, char **argv) {
literal b = foo();
printf("%s", b.s);
return 0;
}
The code prints "foo" correctly on GCC 4.5.4

Leaving out forward declarations (prototypes)

I'm up to lesson 14 on the famous "Learn C The Hard Way" online course.
In that lesson, it introduces the concept of forward declarations in C.
There are two forward declarations in the code sample. One of them can be commented out, and the code still compiles, but the other one cannot be commented out. To me they both look equally as important.
Here's the code. It simply prints out all characters and their hex codes if they are from the alphabet, otherwise it skips them.
The two compiler outputs are at the bottom of the code.
Could someone explain why one errors out and the other one doesn't?
#include <stdio.h>
#include <ctype.h>
// forward declarations
int can_print_it(char ch); //NOT OK to skip(??)
void print_letters(char arg[]); //OK to skip(??)
void print_arguments(int argc, char *argv[])
{
int i = 0;
for(i = 0; i < argc; i++) {
print_letters(argv[i]);
}
}
void print_letters(char arg[])
{
int i = 0;
for(i = 0; arg[i] != '\0'; i++) {
char ch = arg[i];
if(can_print_it(ch)) {
printf("'%c' == %d ", ch, ch);
}
}
printf("\n");
}
int can_print_it(char ch)
{
return isalpha(ch) || isblank(ch);
}
int main(int argc, char *argv[])
{
print_arguments(argc, argv);
return 0;
}
If I comment out the first forward declaration (first one only), this happens:
cc -Wall -g ex14.c -o ex14
ex14.c: In function ‘print_letters’:
ex14.c:24:9: warning: implicit declaration of function ‘can_print_it’ [-Wimplicit-function-declaration]
ex14.c: At top level:
ex14.c:32:5: error: conflicting types for ‘can_print_it’
ex14.c:33:1: note: an argument type that has a default promotion can’t match an empty parameter name list declaration
ex14.c:24:12: note: previous implicit declaration of ‘can_print_it’ was here
make[1]: *** [ex14] Error 1
make[1]: Leaving directory `/home/andrew/c_tutorials/lesson14/ex14_original'
make: *** [all] Error 2
And if I comment out the second declaration (second one only), this happens:
cc -Wall -g ex14.c -o ex14
ex14.c: In function ‘print_arguments’:
ex14.c:13:9: warning: implicit declaration of function ‘print_letters’ [-Wimplicit-function-declaration]
ex14.c: At top level:
ex14.c:17:6: warning: conflicting types for ‘print_letters’ [enabled by default]
ex14.c:13:9: note: previous implicit declaration of ‘print_letters’ was here
make[1]: Leaving directory `/home/andrew/c_tutorials/lesson14/ex14_original'
Well compiler hints why this does happen. The crucial thing it here:
ex14.c:32:5: error: conflicting types for ‘can_print_it’
ex14.c:33:1: note: an argument type that has a default promotion can’t match an empty parameter name list declaration
The argument for can_print_it has a default promotion, therefore it cannot have an implicit declaration. Great read on it is here: Default argument promotions in C function calls. Basically, the argument type for can_print_it (char) is illegal to be used with implicit declarations. To make it work, you would need to use appropriate type, for char it is int. For other types you can check out the linked question and answer.
The print_letters has no such arguments its argument is of a pointer type.
Side-note: As one could see, with 3 wrong answers, people get confused. Implicit declarations are not used often and can be tricky. IMO in general, or at least practical applications, their usage is discouraged. Nevertheless, they are perfectly legal.
You give a function prototype so the compiler knows what to do when it first comes across that function in your code. Specifically, if it has no other information, the compiler will
assume that the return value is an int
promote arguments:
"integer types" to int (so char becomes int, for example)
promote float to double
pointers become pointers to int
The problem is that when you convert a char to an int, it is possible that the significant byte ends up offset by (for example) 3 bytes from where you thought you stored it - since a value like 0x33 might be stored as 0x00000033. Depending on the architecture of the machine, this will cause a problem.
The same is not true with pointers. A pointer "always" has the same size, and always points to the first byte of the object (this wasn't always true... some of us remember "near" and "far" pointers, and not with nostalgia). Thus, even though the compiler may think it is passing a pointer to an int, the subsequent interpretation (by the function-that-had-not-been-declared) as a pointer to a char does not cause a problem.
The fact that your second function is declared as void when the compiler assumed it would return int does not matter, since you never used its return value (which it doesn't have) in an assignment or expression. So even though it's a bit confusing for the compiler, this generates only a warning, not an error. And since the argument is a pointer, the promotion rules again don't cause a conflict.
That said - it is a good idea to always declare your function prototypes before using them; in general, you should turn on all compiler warnings, and improve your code until it compiles without warnings or errors.

C printf printing random number

I am very new to C Programming and have a doubt... I've been asked to find errors in certain segments of C code... and this segment has me a bit confused so would appreciate the help...
int main(void)
{
int myInt = 5;
printf("myInt = %d");
return 0;
}
As far as i understand there is nothing wrong in this code. What i wanna know is why is this statement printing out a random number ??
The output i get is
myInt = 1252057154
Would appreciate the help... Thanks
You should read more about C programming.
And you should enable all warnings and debugging when compiling. With GCC, this means gcc -Wall -Wextra -g (on Linux at least).
When compiling with
gcc -Wall -Wextra -g john.c -o john
I am getting the following warnings:
john.c: In function ‘main’:
john.c:4:5: warning: implicit declaration of function ‘printf’ [-Wimplicit-function-declaration]
john.c:4:5: warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]
john.c:4:5: warning: format ‘%d’ expects a matching ‘int’ argument [-Wformat]
john.c:3:9: warning: unused variable ‘myInt’ [-Wunused-variable]
So the correction is simple:
/* file john.c */
#include <stdio.h>
int main(void)
{
int myInt = 5;
printf("myInt = %d\n", myInt);
return 0;
}
which gets compiled without warnings.
Notice the \n at the end of printf format string. It is important.
Always enable all the warnings the compiler can give you and trust the compiler, so correct your code till no warnings is given.
And learn to use the debugger (e.g. gdb on Linux).
The behavior you observed is undefined behavior; anything could happen with a standard conforming implementation of C (even an explosion).
Happy hacking.
printf (and similarly scanf) works like this:
Let's say you issue a call to printf
printf("%d some text %f %u %hu some more text\n", arg1, arg2, arg3, arg4)
printf goes over the format string and replaces %? with an argument, based on ?
%d some text %f %u %hu some more text
| | | |
arg1 arg2 | arg4
arg3
Now the thing with functions taking variable number of arguments is that, they don't know if the arguments exist, that's why they just take data from a specific part of the stack based on the format string. If you write:
printf("%d %f %u\n");
it reads three non existing data from the stack, most probably get the values stored when calling the function (values that should be hidden from you)
Well, if it's printing something wrong, the problem is in the printf call:
printf("myInt = %d");
Which arguments you're expected to pass?
It should be this:
printf("myInt = %d",myInt);
If you don't include the variable, then it basically pulls a random chunk of memory in. In addition, it might cause more wierd stuff to happen if you do this with a larger chunk of code. Always make sure that you have as many variables from a printf statement as you need, or bad stuff will result.
printf is a function that receives one or more arguments.
In your case it received only one argument (which is legal) but the argument containes %d which tells printf to take the second argument instead of the %d.
printf takes the "second argument" from the stack, and because only one argument was pushed to the stack (the string), it uses the return address as the second argument.
int main(void)
{
int myInt = 5;
printf("myInt = %d",myInt);
return 0;
}
The only change in the code is I added myInt variable in the printf statement if you see at the end.Whenever a variable is assigned some value it can be displayed only by passing it to the printf() function with the corresponding type specifier.Its a rule in C.

Why does atoi() cause a bus error?

#include <stdlib.h>
#include <stdio.h>
main()
{
const char* str_int = "777";
const char* str_float = "333.3";
int i = atoi(str_int);
float f = atof(str_float);
printf("%s %s", i, f);
}
I have tried several bits of example code I‛ve found online, and all of them cause bus errors. Why is this happening?
Your printf is incorrect. Try this instead:
printf("%d %f", i, f);
The problem is that your format specifiers are %s, which expect strings. But you gave it an intand a float. Therefore the result is undefined behavior.
The reason why it's crashing is because printf will try to read the parameters as strings (which are pointers) and deference them as such, but they are invalid pointers.
Here's a reference on printf and its format specifiers:
http://www.cplusplus.com/reference/clibrary/cstdio/printf/
Please take the habit of asking warnings from your compiler. With gcc it is the -Wall option and (on Linux/Debian/Sid gcc 4.6) I'm getting with your example file david.c using the gcc -Wall -g -o david david.ccommand:
david.c:4:1: warning: return type defaults to 'int' [-Wreturn-type]
david.c: In function 'main':
david.c:11:5: warning: format '%s' expects argument of type 'char *', but argument 2 has type 'int' [-Wformat]
david.c:11:5: warning: format '%s' expects argument of type 'char *', but argument 3 has type 'double' [-Wformat]
david.c:12:1: warning: control reaches end of non-void function [-Wreturn-type]
A newbie should correct his code till the compiler gives no more warnings. There are very very rare cases when leaving a warning is acceptable (it should happen less than once a year for a seasoned C programmer).
It's not, printf is. You're telling printf that you're passing it two strings ("%s"), when in fact you're passing an int and a float. It should be:
printf("%d %f", i, f);
Otherwise it'll treat the two arguments on the stack as strings (ie. char*).
Since two char*s haven't been passed as promised, when it tries to print the values of what it thinks are two strings on the stack, it'll cause undefined behaviour and potentially crash. This is most likely because the pointers it's trying to dereference are invalid and don't in fact point to a valid address.
printf has no way of telling if the arguments you're passing are correct, your compiler warnings however will. Turn up your compiler warnings.
Read here for more about warning options with gcc (if that's what you're using): http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
Read here for more about the format specifiers (ie. %s, %d): http://www.cplusplus.com/reference/clibrary/cstdio/printf/
Printf is not correct.Change it to
printf("%d,%f",i,f);
Refer this link to understand the printf syntax clearly:
http://www.codingunit.com/printf-format-specifiers-format-conversions-and-formatted-output

Resources