0

This is the code:

    #include<stdio.h>
    #include<string.h>
    int main()
    {
       char *s = "name";
       int n = strlen(s);
       int i;
       s = &s[n+1];
       for(i=0; i<=n; i++)
       {
          printf("%d %c",i,*s);
          s++;
       }

        return 0;
    }

Output:

0 %1 d2  3 %4 c

I am unable to understand the output. Why its printing % although there's no escape sequence.

mlemboy
  • 387
  • 2
  • 3
  • 15
  • What you are trying to do??? – Jeyaram Jul 18 '13 at 06:01
  • 5
    It's printing your format string... `s` points nowhere it's allowed to point to. Undefined behavior. – Mat Jul 18 '13 at 06:02
  • you go to far, in the current exemple you are displaying the character of you'r first argument in printf but still I don't understand what you are trying to do – Alexis Jul 18 '13 at 06:04
  • Also note that you should declare `s` with: `const char *s = "name";` because it points to a literal and thus it *must* be considered `const`. – Nikos C. Jul 18 '13 at 06:04
  • @Jeyaram My colleague told me he read that if a pointer is pointed to end of string, rotates through string. – mlemboy Jul 18 '13 at 06:05
  • 4
    @mahesh tell him he is wrong :) – Jeyaram Jul 18 '13 at 06:06
  • 4
    @mahesh he is wrong, it doesn't rotate through string. But compiler can rotate your head instead for UB. Beware :) – VoidPointer Jul 18 '13 at 06:06
  • 1
    Oh c'mon I'm just asking some doubts. Please no negative voting. ;) – mlemboy Jul 18 '13 at 06:12
  • @Antonio Literals are constant also in C. Declaring it as `const char*` is a good idea because trying to modify it would be UB. If you really don't want it to be `const`, then you should declare it as `char s[] = "name";` which gets you an array rather than a pointer. – Nikos C. Jul 18 '13 at 06:16
  • consider @Mat 's comment that is your answer. (I think what you wanted) – Grijesh Chauhan Jul 18 '13 at 06:37
  • 1
    [Undefined behaviour](http://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior) – Suvarna Pattayil Jul 18 '13 at 07:10

9 Answers9

4

This line s = &s[n+1]; is causing your pointer to point off into the middle of nowhere. After that you start reading random garbage from it. Apparently that random garbage includes some % characters.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • But every time its giving same output, can you explain this. – mlemboy Jul 18 '13 at 06:06
  • 3
    @mahesh No, there's no explanation for undefined behavior. Just **stop doing this.** –  Jul 18 '13 at 06:07
  • 4
    @mahesh: *undefined behavior* means there's no guarantee. It could crash from trying to read a memory area that doesn't exist. It could give different garbage each time you run. Or it could give the same garbage each time. Since you're reading off the end of a string literal, getting the same garbage each time is the most likely occurrence... but again, it's not guaranteed. – Ben Voigt Jul 18 '13 at 06:10
  • @mahesh: It is not defined by the standard means that at any moment it can change. If you see the same output everytime, then the compiler, environment happens to be identical on each execution, but this does not gurantee that it will be the same always. – phoxis Jul 18 '13 at 06:10
  • same on gcc and turboc(i regret using it). – mlemboy Jul 18 '13 at 06:13
  • @mahesh yes probably getting same but its non-standard in Theory. You can't trust with all compilers and OS, – Grijesh Chauhan Jul 18 '13 at 06:32
1

First assign s = &s[n+1]; then access out of bound memory in printf using *s. code is runing under Undefined behavior according to C standards.

Maximum index to s[] can be length of string that contains \0. Remember index value start from 0 to size of (array/string)-1

Your string is stored in memory something like:

 s           23   24   25   26   27   28
+----+      +----+----+----+----+----+----+
| 23 |      | n  | a  | m  | e  | \0 |  ? |    
+----+      +----+----+----+----+----+----+
              0     1    2    3   4    5

s points to string "name"  
string length of "name" is 4
length("name")  + 1 = 5 
? means garbage values 

In expression s = &s[n+1];, n + 1 is five 5 that pointing to a location outside allocated memory for "name" string And in printf statement you access memory using * Dereference operator cause invalid memory access and behavior of this code at run time is Undefined. That is the reason you code behaving differently at different execution.

Your code compiles correctly because syntactically it correct, But at runtime access of unallocated memory can be detected by OS kernel. This may causes OS kernel send a signal core dump to the your process which caused the exception. (interesting to note: as OS detects memory right violation by a process -- An invalid access to valid memory gives: SIGSEGV And access to an invalid address gives: SIGBUS). In worth case your program may execute without any failure it produces garbage results.

Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
  • Yeah you're right but how come every time its giving same output if its undefined behavior. – mlemboy Jul 18 '13 at 06:08
  • @mahesh http://en.wikipedia.org/wiki/Undefined_behavior may give same output because even at different execution `s` points to same memory address. But the code ruining under Undefined behaviour its **NOT a reliable Code** , can be crash – Grijesh Chauhan Jul 18 '13 at 06:16
  • @mahesh do you wants why you getting same output?? you have to understand at low level. if you wants I can explain in comment. (but it would be against C standards) – Grijesh Chauhan Jul 18 '13 at 06:30
0

s = &s[n+1]; is assignment from out of bound. value of s[n] is '\0' and after this which is s[n+1] will have some garbage value.

Assignment shown above is assigning base address of s[n+1] to s and later you are trying to print values from this new s so all values will be garbage.Accessing out of bound is Undefined behaviour.

Dayal rai
  • 6,548
  • 22
  • 29
0
s = &s[n+1];

Makes s to point unknown memory. Referring s thereafter invokes undefined behavior and anything may happen when you access it in printf.

VoidPointer
  • 3,037
  • 21
  • 25
0

Undefined behaviour because whenever you do s[n+1] where n is the length of the string. Also you are assigning this new address into s again. Accessing every index starting from this location will result in undifined behaviour, because you have no idea what lies at those locations, and you have access to it or not.

You may try defining another string immediately after the one you defined.

char *s = "name";
char *d = "hello test";

In that case you might end up printing the characters from the string "hello test", if the compiler happens to store the string immediately after the string "name" in the read only area. This is not guranteed.

The bottom line is that, the piece of code is not correct and results in undefined behaviour.

phoxis
  • 60,131
  • 14
  • 81
  • 117
0

You are changing the pointer of s to the end of your screen, that's why you have some random garbage.

If for exemple you change your main to

void foo(char *str)
{}

int main()
{
  char *s = "name";
  int n = strlen(s);
  int i;

  s = &s[n+1];
  foo("Test");
  for(i=0; i<=n; i++)
    {
      printf("%d %c\n",i,*s);
      s++;
    }

  return 0;
}

I think it will display test

But you should not do such thing.

Alexis
  • 2,149
  • 2
  • 25
  • 39
0

You asked:

Why its printing % although there's no escape sequence.

The escape sequence to print a % only applies when you are trying to print the % from within the format string itself. That is:

printf("%% %d\n", 1);
/* output:
% 1
*/

There is no need to escape it when it is being provided as the argument for the format conversion:

printf("%s %c\n", "%d", '%');
/* output:
%d %
*/

Your program invokes undefined behavior, since you are making s point one past the last valid object to which it is pointing to (which is allowed), and then you are reading from it (and beyond) during the printing loop (which is not allowed). Since it is undefined behavior, it could do nothing, it could crash, or it could create the output you are seeing.

The output you are getting can be obtained from the following program:

#include <stdio.h>
int main () {
    const char *s = "%d %c";
    int i;
    for (i = 0; i < 5; ++i) {
        printf("%d %c", i, *s);
        s++;
    }
    puts("");
    return 0;
}

/* output is:
0 %1 d2  3 %4 c
*/

This output would be less strange if there was a delimiter between each call to printf. If we add a newline at the end of the output after each call to printf, the output becomes:

0 %
1 d
2  
3 %
4 c

As you can see, it is simply outputting the string pointed to by s, where each character it prints is preceded by the index position of that character.

jxh
  • 69,070
  • 8
  • 110
  • 193
0

in your program:

n = 4;
s = &s[n + 1] = &s[5];

pointer s points to a memory not uninitialized, so the output should be uncertain!

isayme
  • 309
  • 2
  • 11
0

As many people have pointed out, you have moved the pointer s past the end of the static string.

As the printf format string is also a static string there is a chance that the memory next to the static string "name" is the printf format string. This however is not guaranteed, you could just as well be print garbage memory.

jfagan
  • 21
  • 3