0

Why does printing a character with %s gives a segmentation fault everytime?

#include <stdio.h>

int main()
{
  char c = 'a';
  printf("%s",c);
    return 0;
}

if may be it's due to not getting '\0' and it continues to read unless accessing read only memory locations, why does this happens all the time? (as it should get \0 somewhere (most probably) as this code does

#include <stdio.h>

int main()
{
  char c[2];
  c[0] = 'a';
  c[1] = 'a'; //skipping '\0'
  printf("%s",c); //aa..(then some random output)
    return 0;
}

Sorry If the question was silly, I am just a beginner.

Snowfox
  • 69
  • 2
  • 9
  • 2
    you got it .. using the wrong format specifier invokes undefined behavior. It doesn't seg fault "every time" for all conditions on all systems. Just so happens the conditions are right on your system right now that it's segfaulting. Use `"%c"` to print a character. `"%s"` tells `printf` to keep printing until it encounters the terminator, it appears that's not happening before it touches some memory it's not allowed to touch. If you change the compiler flags, use a different compiler, try tomorrow, try running on your buddy's machine, it may not segfault. – yano Apr 04 '19 at 04:07
  • 1
    In the first code, you have `char c = 'a'; printf("%s",c);` — this tries to print the string starting at an address that is represented by the value in `c` and some other bytes. That isn't a valid address, and on your machine triggers a crash. You would need `printf("%s", &c);` to pass a valid address, but that would lead to problems with sundry other characters being printed because the chances are there wouldn't be a null `'\0'` after the `a`. That's more or less what's going on in your second fragment. – Jonathan Leffler Apr 04 '19 at 04:13
  • 1
    @yano: even worse, it is not actually printing the character, but interpreting the character as a pointer to see what to print. It is extremely likely that pointer is pointing to memory region that is off limits, thus segv. It doesn't even come to looking for a zero. – Amadan Apr 04 '19 at 04:13
  • 1
    read compiler warnings and it'll tell you the problem immediately – phuclv Apr 04 '19 at 04:16
  • Possible duplicate of [Crash or "segmentation fault" when data is copied/scanned/read to an uninitialized pointer](https://stackoverflow.com/questions/37549594/crash-or-segmentation-fault-when-data-is-copied-scanned-read-to-an-uninitializ) replace "uninitialize" by "invalid" the answer is the same – Stargateur Apr 04 '19 at 05:25
  • `%s` is for strings only, `char`s have to be `printf()`d with `%c`. – Luis Colorado Apr 04 '19 at 12:00
  • @Amadan Ah yes, absolutely correct – yano Apr 04 '19 at 14:40

3 Answers3

4

Why does printing a character with %s gives a segmentation fault everytime?

Because %s tells printf that the argument is a pointer to a string, and because most modern systems protect low-address memory from all accesses (to prevent bugs like this from staying undetected).

When you pass 'a', to printf, it gets a value 0x41 (ASCII code for a), interprets that value as a pointer, which points into the lowest page of memory, which is protected with no-access -> SIGSEGV.

Employed Russian
  • 199,314
  • 34
  • 295
  • 362
0

Because of %s printf is expecting a pointer to a string . So while printing printf tries to print from address the c(value of c) stores which could be invalid(Because it's not actually an address), hence resulting in segfault.

You could do printf("%s", &c); // this could produce some Garbage values

Mohit Jain
  • 270
  • 2
  • 6
0

This is what you intend to do:

#include <stdio.h>

int main()
{
    char c = 'a';
    printf("%c",c);  /* <<<< use %c instead of %s, read printf(3) */
    return 0;
}

If you do:

#include <stdio.h>

int main()
{
    char c[2];
    c[0] = 'a';
    c[1] = 'a'; //skipping '\0'
    printf("%s",c); //aa..(then some random output)
    return 0;
}

this time you are passing printf() a pointer (the array name c alone is interpreted as the address to the first element, so it can be passed to printf() with the %s format specifier. This time, the lack of a \0 makes printf() to continue printing until it gets a \0, you can change your code into:

#include <stdio.h>

int main()
{
    char c[2];
    c[0] = 'a';
    c[1] = '\0';
    printf("%s",c); // you get only a
    return 0;
}

and you'll get a as printed output.

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31