C – how/why does this piece of code “work”?

  • A+
Category:Languages

I've written this code and "it works" — but how?

I haven't declared an array in my main function; I simply added a standard integer into a procedure with a pointer. For example, it'll scan an array of 2 or 20 integers by changing how many times the loop will run.

#include <stdio.h>  void test(int *v, int n) {     int i;     for (i = 0; i < n; i++) {         printf("[%d]: ", i);         scanf("%d", &v[i]);      }     printf("/n/n#############/n/n");     for (i = 0; i < n; i++) {         printf("[%d]: %d/n", i, v[i]);     } }  int main(void) {     int array;     int t = 10;      test(&array, t);     return 0; } 

I didn't really know exactly what I was writing, until I realized it was working. I've tried to search about "array of pointers", or pointers in general but couldn't find any specific answer to this example above. I wish I knew more what exactly to look for.


This code works, for only for some values of the word "work" :-)

Your test function wants the address of an integer and a integer count. The main function gives it exactly those things, &array and t. So it compiles just fine.

However, the instant you try to de-reference v[1] or even calculate the address of v[N] where N is neither zero nor one, all bets are off. You have given an array of exactly one element and it's undefined behaviour to do either of those mentioned things

So, while your code may seem to work(a), that will be entirely by accident and not guaranteed on another implementation, another machine, or even during a different phase of the moon.

You can, of course, fix this by ensuring you don't try to do anything beyond the end of the array. with something like:

int array; test(&array, 1); 

or:

int array[42]; test(array, sizeof(array) / sizeof(*array)); 

This will ensure the count values passed through to the function matches the size of said array.


For the language lawyers amongst us, C11 Appendix J.2 lists these items as being undefined behaviour (the first covers calculating v[N] where N is neither zero nor one, the second covers de-referencing v[1]):

Addition or subtraction of a pointer into, or just beyond, an array object and an integer type produces a result that does not point into, or just beyond, the same array object (6.5.6).

Addition or subtraction of a pointer into, or just beyond, an array object and an integer type produces a result that points just beyond the array object and is used as the operand of a unary * operator that is evaluated (6.5.6).

That referenced 6.5.6 /8 states:

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.


(a) The possibility that undefined behaviour sometimes "works" is actually its most insidious feature. If it never worked, it would be so much better.

That's why I have a patent pending(b) on a device that connects electrodes to your private parts that get activated whenever the compiler detects use of said behaviour.

It has increased considerably the quality of the code our shop delivers. Now if only we could retain our staff, that would be excellent :-)


(b) Not really, I seem to recall there's an actual legal issue with claiming patent pending status untruthfully so I need to clarify that this was for humour value only.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: