I have this code:
#include <stdio.h>
#include <string.h>
void main(){
printf("%p");
}
This is the output:
0x7ffdd9b973d8
I know %p stands for pointer and when using it as for example
#include <stdio.h>
#include <string.h>
void main(){
int i = 0;
printf("%p", i);
}
it returns the pointer address of i. But my question is what does it return when not adding any other argument in the printf function just printf("%p")
Trash. printf uses a variable-length argument list. It uses the format string to determine how many arguments you actually passed. If you did not actually pass anything in, it will still read from basically arbitrary portions of memory as though you did. The result is undefined/trash.
Some compilers will be able to catch this situation with a warning because the printf family of functions is so popular. Some cases may crash your system if the function tries to read from memory you do not have access to. There is no way to tell how it will behave next time even if you have obtained a certain result.
But my question is what does it return when not adding any other argument in the printf function just printf("%p");
Anything. Nothing. Random junk. Maybe it crashes.
There is no way to know without investigating a specific combination of compiler, CPU, platform, libraries, execution environment, and so on. There is no rule that requires it to operate any particular way.
The behavior of
printf("%p");
is undefined. When you specify a %p format in the format string, the corresponding argument of void * (or char *) type shall be present in the argument list.
Related
I'm creating my own kind of C library with my own kind of functions and also to help be better understand C and not just depend on GNU C Library for everything.
So far I got a bit of functions running but I wan't to tweak my printo function a little bit to support unlimited arguments (Restricted to chars only but your answer may also support passing in integer arguments). Here is the printo code:
#include "../GV.h"
#include "OtherUtils.h"
int print(char *WRITEOUT1){
char *WRITEOUT=&WRITEOUT1[0];
int AMOUNT=GetCharSize(WRITEOUT1);
register int SYSCALLNO asm("rax")=SYSWRITE;
register int FD asm("rdi")=STANDARDFD;
register char *BUF asm("rsi")=WRITEOUT;
register int BYTES asm("rdx")=AMOUNT;
asm("syscall");
return 0;
}
GetCharSize function code if anyone needs it:
#include "../GV.h"
int GetCharSize(char *arg){
for(i=0;arg[i]!='\0';i++){
}
return i;
}
GV.h has variables defined like int i;
Before I asked this question I looked into C pre-processors like __VA_ARGS__ but I somewhat couldn't wrap my head around it.
The ... notation is a part of the syntax of the C language. It is used in defining the argument list of a function as the last argument and means "followed by zero or more arguments of any type". E.g.
int printf (char *format, ...);
A function defined in this way can now be called with all the mandatory arguments, plus any number of additional arguments, like printf.
A function defined is this way must have a means of knowing how many arguments there are, and what the type of each argument is. printf knows this from the format specification string, the only required argument of printf.
Assuming an Intel system that uses a stack to pass arguments, and where arguments are pushed right-to-left (last argument pushed first), so the first optional argument will be directly after the format specification string on the stack, printf now proceeds as follows: take the address of the format specfication string and increment that address with the size of a char *. This is the start of the optional arguments. Now look at the format specifier string to know the type of the next argument; get that type of argument from the stack, increment it with the size of that argument to get the next address. Do this until there are no more format specifiers.
I am using ctime. However it always returns NULL. So it cores on sprintf line. It worked earlier. So not sure why it is randomly returning NULL?
I have the following code snippet:
int main()
{
char avp_val[50];
uint32_t date_value=1477069401;
sprintf(avp_val,"%s",ctime((time_t*)(&date_value)));
return;
}
Don't cast a pointer to uint32_t to a time_t. Use an actual time_t, so on systems with 64 bit time_t ctime isn't reading four bytes of garbage as part of the epoch time:
int main()
{
char avp_val[50];
time_t date_value=1477069401;
sprintf(avp_val,"%s",ctime(&date_value));
// Or, because it's what you're doing anyway, skip sprintf:
// strcpy(avp_val, ctime(&date_value));
return 0;
}
Casting to (time_t*) to silence compiler warnings silenced the warnings, it didn't fix the problem.
Well, your code lacks a bunch of include files:
#include <stdlib.h> /* for the types you use below, like uint32_t */
#include <stdio.h> /* for a prototype for sprintf, which you use below */
#include <time.h> /* for a prototype for ctime() see NOTE 1 */
You must also take into account that casting must be done with data values, not with pointers, as casting a pointer only bypasses the compiler type checking system and makes your code more error prone. In this case you conversion from uint32_t * to time_t * is too dangerous if both types happen to have different sizes, as you'll be cutting the value using only half the bits required. This is something knows as Undefined Behaviour and you should avoid it.
You also have to return an explicit value from main. It's a compile error not to do so, so your example cannot execute, because it does not compile (and so, you cannot receive NULL from ctime(3))
By the way, I tried your code with uint32_t date_value in a mac OS/X and it printed the right value of time, so probably time_t is a 32 bit value, but you had better to use a time_t as it is defined by that reason.
NOTE 1
The most important in this case is the prototype of ctime(), which returns a pointer to char and without a prototype, the compiler assumes it returns an int. At least, in 64bit platforms, both types are different sizes, and cannot be passed this way.
Please, always post a Complete, minimum, verifiable example, as you can hide the exact source of the error by editing your example to be shown.
A few years back i was working with Turbo C compiler and the following code worked fine on it.
#include<stdio.h>
void main()
{
int a=2,b=3;
swap(a,b);
printf("%d\n%d\n",a,b);
}
swap(int *x,int *y)
{
int t;
//x=malloc(2);
//y=malloc(2);
t=*x;
*x=*y;
*y=t;
printf("%d\n%d\n",x,y);
}
Now i am working on cygwin and if i run this code i get an error Segmentation fault(core dumped)
If i uncomment the malloc statements i get the output
536937064
536937080
2
3
Are first two lines of output some garbage values? What exactly is happening here and how can i get the correct output?
Here is the corrected version of your program, which will execute correctly.
There are a number of things going wrong in the sample you posted:
Incorrect Argument type being passed:
swap(a,b);
should be :
swap(&a,&b);
Your function expects pointer to the integers to be modified, You are not doing so.
Incorrect Format specifiers for printf:
printf("%d\n%d\n",x,y);
should be:
printf("%d\n%d\n",*x,*y);
printf is not type safe and you need to ensure you use proper format specifiers while using it. Using incorrect format specifiers results in Undefined Behavior.
The next two are good practices if not errors and you should follow them.
Incorrect return type of main():
As per the Standard a program should return int,
void main()
should be
int main()
Also, add return a value return 0;at the end of main.
Function Declaration:
You should declare the function swap() correctly before main:
void swap(int *x,int *y);
Providing a function declaration before the place where you use it in code, gives the compiler a opportunity to match the parameters and report incorrect types being passed.
Further using malloc as you have would not acheive what you are trying to achieve, You do not need to use malloc here at all and One should always avoid using it as much as possible.
Also, You should pick up a good book and learn the basics.
Nothing here is actually correct.
The parameters to swap are the literal addresses 2 and 3. You can &a and &b in the call.
printf in swap is printing the pointer addresses, so the output is "expected".
If you were using malloc (why?), you are only allocating 2 bytes. An int is generally 4 , but please use sizeof.
You are passing values of the variables and using pointers to receive it.
`swap(a,b) `
should be swap(&a,&b)
because you must pass the address of the variables, not the variable itself. Read Call by reference in C.
#include <stdio.h>
void littledot(){}//must use C, not C++
int main() {
littledot(568,76,105,84,116,76,101,68,111,84);
printf("%c%c%c%c%c%c%c%c%c\n");
getchar();
return 0;
}
The above code yields the result "LiTtLeDoT". Why does it do that? Why is 568 crucial?
This differs per platform and is UB (the implementation can do anything it wants*), but probably the arguments to littledot() are still on the stack after littledot() returns and printf prints those arguments from the stack.
NEVER RELY ON THIS!
*really anything. Afaik an ancient version of GCC started a videogame when it encountered something that would behave in an undefined way.
You were lucky. This is undefined behaviour, specifically the call to printf. The program could do anything. Your implementation happens to write "LiTtLeDoT".
The really is the nature of undefined behaviour. The compiler can do anything it wants. If you really want to know why it does what it does then you will need to look at the emitted object code. Looking at the C code will yield nothing because of the aforementioned undefined behaviour.
This is what's working reliably for me with Open Watcom 1.9 on Windows:
//must use C, not C++
#include <stdio.h>
#include <stdlib.h>
void
__stdcall // callee cleans up
littledot()
{
}
int main(void)
{
littledot(/*568,*/'L','i','T','t','L','e','D','o','T');
printf("%c%c%c%c%c%c%c%c%c\n");
getchar();
exit(0);
return 0;
}
littledot() is called with a number of parameters that are passed on the stack.
If the calling convention for littledot() is __stdcall (or __fastcall), it will have to remove its parameters from the stack.
If it's __cdecl, then main() will have to remove them, but this won't work for us.
However, littledot() doesn't and can't do anything about the parameters because they're not specified, which is something you can do in C, but not C++.
So, what happens is that not only littledot()'s parameters remain on the stack after the call to it, but also the stack pointer is not restored (because neither littledot() nor main() remove the parameters, which is typically done by adjusting the stack pointer) and the stack pointer points to 'L'. Then there's the call to printf() that first places on the stack the address of the format string "%c%c%c%c%c%c%c%c%c\n" thus forming all expected parameters for the function on the stack. printf() happily prints the text and returns.
After that the stack isn't correctly balanced and doing return in main() is risky as the app may crash. Returning by means of exit(0) fixes that.
As all others have said, none of this is guaranteed to work. It may only work with specific compilers for specific OSes and then only sometimes.
http://codepad.org/tfRLaCB5
I'm sorry, what you claim the program to print is not what happens on my box and not what happens on codepad's box.
And the reason is, the program has undefined behavior. printf expects one additional argument (an int) for every %c you have in the format string. You don't give it those arguments, hence anything can happen.
You are in a situation where with certain implementations of printf, compiler options, certain compilers and certain ABIs, you end up with that output. But you should not think that this output is required by any specification.
int main()
{
int j=97;
char arr[4]="Abc";
printf(arr,j);
getch();
return 0;
}
this code gives me a stack overflow error why?
But if instead of printf(arr,j) we use printf(arr) then it prints Abc.
please tell me how printf works , means 1st argument is const char* type so how arr is
treated by compiler.
sorry! above code is right it doesn't give any error,I write this by mistake. but below code give stack overflow error.
#include <stdio.h>
int main()
{
int i, a[i];
getch();
return 0;
}
since variable i take any garbage value so that will be the size of the array
so why this code give this error when i use DEV C++ and if I use TURBO C++ 3.0 then
error:constant expression required displayed. if size of array can't be variable then when
we take size of array through user input.no error is displayed. but why in this case.
please tell me how printf works
First of all, pass only non-user supplied or validated strings to the first argument of printf()!
printf() accepts a variable number of arguments after the required const char* argument (because printf() is what's called a variadic function). The first const char* argument is where you pass a format string so that printf() knows how to display the rest of your arguments.
If the arr character array contains user-inputted values, then it may cause a segfault if the string happens to contain those formatting placeholders, so the format string should always be a hard-coded constant (or validated) string. Your code sample is simple enough to see that it's really a constant, but it's still good practice to get used to printf("%s", arr) to display strings instead of passing them directly to the first argument (unless you absolutely have to of course).
That being said, you use the formatting placeholders (those that start with %) to format the output. If you want to display:
Abc 97
Then your call to printf() should be:
printf("%s %d", arr, j);
The %s tells printf() that the second argument should be interpreted as a pointer to a null-terminated string. The %d tells printf() that the third argument should be interpreted as a signed decimal.
this code gives me a stack overflow error why?
See AndreyT's answer.
I see that now the OP changed the description of the behavior to something totally different, so my explanation no longer applies to his code. Nevertheless, the points I made about variadic functions still stand.
This code results in stack invalidation (or something similar) because you failed to declare function printf. printf is a so called variadic function, it takes variable number of arguments. In C language it has [almost] always been mandatory to declare variadic functions before calling them. The practical reason for this requirement is that variadic functions might (and often will) require some special approach for argument passing. It is often called a calling convention. If you forget to declare a variadic function before calling it, a pre-C99 compiler will assume that it is an ordinary non-variadic function and call it as an ordinary function. I.e. it will use a wrong calling convention, which in turn will lead to stack invalidation. This all depends on the implementation: some might even appear to "work" fine, some will crash. But in any case you absolutely have to declare variadic functions before calling them.
In this case you should include <stdio.h> before calling printf. Header file <stdio.h> is a standard header that contains the declaration of printf. You forgot to do it; hence the error (most likely). There's no way to be 100% sure, since it depends on the implementation.
Otherwise, your code is valid. The code is weird, since you are passing j to printf without supplying a format specifier for it, but it is not an error - printf simply ignores extra variadic arguments. Your code should print Abc in any case. Add #include <stdio.h> at the beginning of your code, and it should work fine, assuming it does what you wanted it to do.
Again, this code
#include <stdio.h>
int main()
{
int j=97;
char arr[4]="Abc";
printf(arr,j);
return 0;
}
is a strange, but perfectly valid C program with a perfectly defined output (adding \n at the end of the output would be a good idea though).
In your line int i, a[i]; in the corrected sample of broken code, a is a variable-length array of i elements, but i is uninitialized. Thus your program has undefined behavior.
You see strings in C language are treated as char* and printf function can print a string directly. For printing strings using this function you should use such code:
printf("%s", arr);
%s tells the function that the first variable will be char*.
If you want to print both arr and j you should define the format first:
printf("%s%d", arr, j);
%d tells the function that the second variable will be int
I suspect the printf() issue is a red herring, since with a null-terminated "Abc" will ignore other arguments.
Have you debugged your program? If not can you be sure the fault isn't in getch()?
I cannot duplicate your issue but then I commented out the getch() for simplicity.
BTW, why did you not use fgetc() or getchar()? Are you intending to use curses in a larger program?
===== Added after your edit =====
Okay, not a red herring, just a mistake by the OP.
C++ does allow allocating an array with the size specified by a variable; you've essentially done this with random (garbage) size and overflowed the stack, as you deduced. When you compile with C++ you are typically no longer compiling C and the rules change (depending on the particular compiler).
That said, I don't understand your question - you need to be a lot more clear with "when we take size of array through user input" ...