1
#include<stdio.h>
#include<string.h>

int main() {
    char *ptr = NULL;

    printf("%s", ptr);//The output is null
    //  printf("%s\n", ptr); //addition of **\n** give segmentation fault 

    return 0;
}

the first printf outputs: (null). But why the second printf's output is: Segmentation fault (core dumped) just on adding: \n?

Giorgi Moniava
  • 27,046
  • 9
  • 53
  • 90
Anil Kumar
  • 348
  • 5
  • 16

4 Answers4

10

printf("%s", ptr);

Here printf expects a valid pointer, which points to null terminated string, you can't pass NULL to it. If you do so, you will trigger undefined behaviour, and can't reason about output of the program.

PS. I have found an answer which might have slightly more details about the thing you might be interested in. See here. Actually your question seems to be a duplicate of that one.

Community
  • 1
  • 1
Giorgi Moniava
  • 27,046
  • 9
  • 53
  • 90
  • This is not the real reason behind it, see my answer – Ctx Jan 21 '16 at 12:34
  • @Ctx Isn't what OP has undefined behaviour? That is the only thing stated in my answer. – Giorgi Moniava Jan 21 '16 at 12:35
  • No, it is not, because the reason for the segfault is not this line, but the next one. If you only have one of the two lines in the program, the second one will segfault, while the first will not. – Ctx Jan 21 '16 at 12:36
  • @Ctx: read the many answers here: http://stackoverflow.com/questions/12222447/a-few-questions-about-legal-arguments-to-printfs. Segfault is one thing that can happen if there is UB – Giorgi Moniava Jan 21 '16 at 12:38
  • Ok, that may be the reason why this behaviour is _standard compliant_ but it is not the reason, why it is happening this way! I.e. the difference between _with_ newline and _without_ newline – Ctx Jan 21 '16 at 12:42
  • @Ctx You can expand on that in your answer. All I said there is UB in OPs code - do you disagree? – Giorgi Moniava Jan 21 '16 at 12:43
  • I have done that. But I think, you haven't answered the question which was about the _reason_ of that behaviour, and not about if it is OK or not according to the C-standard. I do not disagree that it is UB – Ctx Jan 21 '16 at 12:45
  • @Ctx If you do not disagree about the UB then there is no point about reasoning why there is some output. – Giorgi Moniava Jan 21 '16 at 12:48
  • If we humans would only observe behaviour and not asking about the _reason_ (causality), _why_ a behaviour is observed, where would we be now? ;) The OP asked for the _reason behind_, which you do not provide, I think. – Ctx Jan 21 '16 at 12:49
  • @Ctx As I said when there is UB you can't provide reason for ANYTHING in the program. – Giorgi Moniava Jan 21 '16 at 12:50
  • So you disagree with my explanation below? Then I would advise you to vote it down and comment what's wrong with it. – Ctx Jan 21 '16 at 12:51
  • @Ctx I recommend you expand your answer by adding more explanations and reasons as to what your version of correct answer is – Giorgi Moniava Jan 21 '16 at 12:53
  • Ok, I have done that. Thank you. – Ctx Jan 21 '16 at 12:58
3

Some printf implementation take care about NULL string parameter, but some of these implementations have "bugs", see gcc printf optimization .

Whatever, C standard says:

the argument shall be a pointer to the initial element of an array of character type

If not, then it is an undefined behavior. The behavior you've faced is one of these.

Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69
3

The technical reason behind is:

If you write a statement like

printf("%s\n", ptr);

some compilers (i.e. gcc with optimizations) will "optimize" it to:

puts(ptr);

The glibc-implementation of puts() doesn't print (null) on a NULL-pointer (as printf does), but happily segfaults.

When gcc is invoked without optimizations activated, this substitution is not made and printf("%s\n", NULL); will not segfault.

This behaviour is standard compliant, since passing a NULL-pointer to printf() invokes "undefined behaviour".

Ctx
  • 18,090
  • 24
  • 36
  • 51
  • "When gcc is invoked without optimizations activated, this substitution is not made and printf("%s\n", NULL); will not segfault." This is wrong - isn't this also UB ? If yes, you can't say whether it will segfault or not. – Giorgi Moniava Jan 21 '16 at 13:00
  • @GiorgiMoniava It is undefined behaviour according to the standard, but this of course doesn't mean that it is exactly determined how glibc-printf with gcc will behave. So, while the code invokes UB, it doesn't mean a concrete binary in a concrete runtime environment behaves indeterministically. – Ctx Jan 21 '16 at 13:17
  • You can also check the link in my updated answer, I think it refers more to what you were trying to say – Giorgi Moniava Jan 21 '16 at 13:21
  • @GiorgiMoniava d'Oh. Reading that question, we can both delete our answers and close this question as duplicate... Nice to meet you ;) – Ctx Jan 21 '16 at 13:22
  • Yeah, I've flagged this as duplicate. Nice meeting too. – Giorgi Moniava Jan 21 '16 at 13:33
-1

As i can make out printf is actually using a system call called write() which will be used by the kernel to write to the stdout file descriptor. In this case the \n causes the pointer to move to unchartered territory and trying to write data from there to the stdout file descriptor causes this behaviour.

Found one good reference from SO itself

C/C++ function definitions without assembly

Community
  • 1
  • 1
achoora
  • 1,270
  • 1
  • 16
  • 32
  • `write()` is called late in -- namely at the very end of -- the processing pipeline which starts with a user program calling `printf()`. `write()` will in all likelihood **not** read the data it transmits to a device from the original string (which doesn't exist here) but from the buffer used by the buffered I/O of the C standard libraries. (Possibly the situation is different with unbuffered I/O. Not sure.) It's not immediately clear how a newline -- which is just a character copied to the output, after all -- should change anything at all. – Peter - Reinstate Monica Jan 21 '16 at 09:31
  • line buffering causes a write() call to be raised when a new line appears in the buffer.Here the buffer is empty(NULL) .The syntax of write {man write(3)} goes like ssize_t write(int fildes, const void *buf, size_t nbyte);So if the buf is NULL while trying to fetch some thing from there it may cause a segfault .I would like to get corrected if the thought process is wrong. – achoora Feb 18 '16 at 12:34
  • 1
    `printf` "causes" (that's correct -- in your post you wrote "is a", which is incorrect) a `write`, true. But `printf` first copies its generated formatted characters into a separate buffer (the one you can set with [`setbuf`](http://man7.org/linux/man-pages/man3/setbuf.3.html)). `write` is called *with that buffer* (not with the original data). That buffer is always ok. What causes trouble here is dereferencing a null pointer *by the printf function* as it tries to copy data over to the internal buffer that the C standard lib has. The call to `write` is never reached. – Peter - Reinstate Monica Feb 18 '16 at 13:42