0
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.

1
  • 2
    What compiler, what platform and please show your #include lines, if not too long. Commented Oct 2, 2010 at 6:50

5 Answers 5

3

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.

Sign up to request clarification or add additional context in comments.

4 Comments

There are use-cases where passing the format argument as non-constant is useful (e.g., when doing i18n and l10n) but it is never a good idea to pass a user-supplied string as the format argument. Indeed, that's been the source of many hacks of programs where the data and code are in different security contexts (e.g., because they are setuid or taking data from the web).
Firstly, I don't see any problems with the string being "non-constant" in this case. It is not user supplied anyway. Secondly, neither in the answer addresses the issue of the crash.
@Donal Fellows: Right. I've modified my answer to not be too restrictive. However, all external data should always be validated.
@AndreyT: The OP asked how printf() works, so I answered that part of the question.
3

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).

14 Comments

So, variadic functions do require special argument handling and it is related to compilation. In fact, that is exactly the reason why ANSI C89/90 explicitly requires such functions to be declared before they are called. (There's no such requirement for ordinary functions in C89/90.) Your remark about "versions of C" is not exactly clear to me. This has nothing to do with nay "versions of C", but everything to do with the detail of various implementations. What I said above is absolutely true for such compilers as GCC and MSVC on x86 platform, for one example.
@AndreyT: considering the vast majority of real-world non-embedded systems are i386 (32-bit x86), I think your claim is grossly incorrect. The i386 ABI does not use any fancy pass-by-register tricks, and in fact due to register starvation they would be largely useless. As far as the C language goes, implementations are of course allowed to use different calling conventions and valid C code must use correct prototypes for variadic functions, but in the world of x86 it's irrelevant.
Standard x86 calling convention ("cdecl" as you call it) is not "performance-destroying" or even sub-optimal on x86. I challenge you to find a single real-world function where you can measure the difference between passing arguments on the stack versus in (the tiny number of) registers. You are correct from a C language perspective that declaring the variadic function is required to avoid UB, but mixing in religious tirades and factually incorrect information about the x86 implementation is not the way to teach people to follow the standard.
@R..: Firstly, the information that I attributed as applying to x86 is absolutely precise and factually correct. Secondly, the performance impact of cdecl convention is noticeable in every computational application I ever worked with. No exceptions. Thirdly, the number of available registers in modern CPUs (x86 again, for example) is already sufficient to cover many (if not most) functions with a reasonable number of parameters. Which is why the performance benefit of fast calling conventions is so huge and so immediately and easily measurable.
Finally, calling such obvious practical considerations as properties of variadic functions (compared to ordinary functions) "religious tirades" is something that fits somewhere between total lack of expertise and plain trolling.
|
1

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.

Comments

0

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

Comments

0

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" ...

3 Comments

printf ignores the extra arguments, but the compiler does not. the stack will be in a state printf doesn't expect, and if the calling convention doesn't handle that gracefully, who knows what will happen.
Actually "the compiler does not" isn't strictly true, since it depends on the compiler, although I don't know of any compilers that will actually generate different code. I'm pretty sure that those which handle it at all at most will generate compile time warnings or errors.
The latest version of C (C99) does allow variable-length arrays. You are correct about the cause of the stack overflow error, though (the indeterminate value of i).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.