-1
main()
{
    char buffer[6]="hello";
    char *ptr3 = buffer +8; 
    char *str;   
    for(str=buffer;str <ptr3;str++)
        printf("%d \n",str);
}

Here, ptr3 is pointing out of array bounds. However, if I run this program, I am getting consecutive memory locations (for ex.1000.....1007). So, according to the C standard, a pointer pointing more than one past the array bound is explicitly undefined behavior.

My question is how the above code results in undefined behavior?

CodeMouse92
  • 6,840
  • 14
  • 73
  • 130
Ronn
  • 9
  • 5
  • Please add a language tag. –  Sep 20 '16 at 16:49
  • You answered your own question. "a pointer pointing more than one past the array bound is explicitly undefined behavior.". Therefore your code results in undefined behaviour becaue it contains `buffer + 8`. – M.M Sep 20 '16 at 23:59

3 Answers3

1

There are multiple occurrences of undefined behavior in your program.

For starters you're calling printf without the required #include <stdio.h>, and main() should be int main(void). That's not what you're asking about, but you should fix it.

char buffer[6]="hello";

This is ok.

char *ptr3 = buffer +8; 

Evaluating the expression buffer +8 has undefined behavior. N1570 6.5.6 specifies the behavior of the + addition operator, and paragraph 8 says:

If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.

Computing the pointer value by itself has undefined behavior, even if you never dereference it or access its value.

char *str;   
for(str=buffer;str <ptr3;str++)
    printf("%d \n",str);

You're passing a char* value to printf, but %d requires an argument of type int. Passing a value of the wrong type to printf also has undefined behavior.

If you want to print the pointer value, you need to write:

printf("%p\n", (void*)str);

which will likely print the pointer value in hexadecimal, depending on the implementation. (I've removed the unnecessary trailing space.)

When str points to buffer[5], str++ is valid; it causes str to point just past the end of buffer. (Dereferencing str after that would have undefined behavior, but you don't do that.) Incrementing str again after that has undefined behavior. The comparison str < ptr3 also has undefined behavior, since ptr3 has an invalid value -- but you already triggered undefined behavior when you initialized ptr3. so this is just icing on the proverbial cake.

Keep in mind that "undefined behavior" means that the C standard does not define the behavior. It doesn't mean that the program will crash or print an error message. In fact the worst possible consequence of undefined behavior is that the code seems to "work"; it means that you have a bug, but it's going to be difficult to diagnose and fix it.

M.M
  • 138,810
  • 21
  • 208
  • 365
Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
0

You are seeing the address of the pointer. If you want the value, you need use the dereference (*) operator in the printf.

The other thing is, if you want see characters and not ASCII codes, you should use %c in printf.

printf("%c\n",*str);
CodeMouse92
  • 6,840
  • 14
  • 73
  • 130
amchacon
  • 1,891
  • 1
  • 18
  • 29
  • This is not what i want.See the reasoning with qus. – Ronn Sep 19 '16 at 16:04
  • @Ronn your code isn't a undefined behaviour. You are seeing memory locations cause the printf – amchacon Sep 19 '16 at 16:05
  • Suppose if i use printf("%c\n",*str); then after Null pointer we accessing the memory location which are uninitialized so will not it causes any problem.? – Ronn Sep 19 '16 at 16:07
  • @Ronn you will see the characters of the array, one in every line. – amchacon Sep 19 '16 at 16:09
  • we can take the address one beyond the end of an array, but you can't dereference it.While going more than one past the array bound is explicitly undefined behavior.Will the above program does not meeting this requirement? – Ronn Sep 19 '16 at 16:14
  • @Ronn Ok, i see now. Yes, the last position indexed is out of bounds. It's an undefined behaviour. Usually you will see garbage, other variables or get kicked by the os. – amchacon Sep 19 '16 at 16:22
  • @ amchacon i want to know why undefined because we will get garbage in every compiler or different version of same compiler ?Means we are getting garbage everywhere.Then why undefined ? – Ronn Sep 19 '16 at 16:27
  • @Ronn it's undefined behavior cause doesn't have any guarantes. – amchacon Sep 19 '16 at 16:29
  • @ronn sometimes it's not garbage, could be other variable's data – amchacon Sep 19 '16 at 16:30
  • @ronn sometimes could enter in protected address, and get kicked by the so – amchacon Sep 19 '16 at 16:30
  • OK but suppose we are running the above program ,it is giving consecutive memory locations(For ex.1000.....1007) in almost all online C compiler.So how can we say pointing beyond one past of array results in undefined behaviour. – Ronn Sep 19 '16 at 16:34
  • @Ronn: You need to understand what "undefined behavior" means. It means that the C standard doesn't tell you how it behaves. Printing the addresses of consecutive memory locations is perfectly consistent with that. – Keith Thompson Sep 21 '16 at 01:51
  • Ok thanks @Keith .Sometime time it is very difficult to trace out undefined behaviour .Then in that case what should we do ? How do we know given C program results in undefined behaviour? – Ronn Sep 21 '16 at 02:01
  • @Ronn: In most cases, the things that the standard leaves undefined are errors that cannot practically be detected at compile time or at run time. There's no general rule to determine which behaviors are defined and which are not -- other than understanding what the standard says about it. Trying to write only code that's obviously correct can also be helpful. For example, `i = i++;` has undefined behavior -- but there's no good reason to write that in the first place; whatever it's supposed to mean, there's a clearer and more reliable way to express it. – Keith Thompson Sep 21 '16 at 19:05
  • @Ronn: Consider grabbing a copy of a draft of the C standard (the latest is [N1570](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf)) and search for the word "undefined". Warning: The standard is a language definition, not a tutorial; don't expect to understand all of it. – Keith Thompson Sep 21 '16 at 19:06
0

In C, you can always add two numbers. You can always add an integer to a pointer, or subtract two pointers. You will always get an "answer": the compiler will generate code and the code will execute. That's no assurance that answer is valid, useful, or even defined.

The C standard defines the language. Within the scope of what the syntax admits, it defines what's valid -- what definitely means something -- and what's not. When you color outside those lines, the compiler may produce weird code or no code. In C, it's not the job of the compiler to anticipate every weird circumstance and arrive at a reasonable answer. The compiler writer assumes the programmer knows the rules, and is not required to verify he followed them.

There are lots of examples of valid syntax that's meaningless or undefined. In math, you cannot take the log of a negative, and you cannot divide by zero. Dividing by zero doesn't yield zero or not zero; the operation is undefined.

In your case, ptr3 has a value, duly computed, 8 larger than buffer. That's the result of some pointer arithmetic. So far, so good.

But just because you have a pointer, doesn't mean it points to anything. (void*) 0 is explicitly guaranteed not point to anything. Likewise, your ptr3 doesn't point to anything. It needn't even be a value 8 larger than buffer. Section 6.5.6 of the C standard defines the result of adding an integer to a pointer, and puts it this way:

If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.

When you say, I am getting consecutive memory locations (for ex.1000.....1007), what you're seeing is behavior. You had to see some behavior. And that behavior is undefined. According to the standard, you could see some other behavior, such as wrapping back to 1000 or 0.

What the compiler accepts and what the standard defines are two different things.

James K. Lowden
  • 7,574
  • 1
  • 16
  • 31