0

in the code:

char * strarray[] = {"first", "second", "third", "fourth", "fifth"};

I thought strarray[5] would be NULL since it is the value outside of the array but it is not and strarray[6] is null.

printf("%d %d\n", NULL == strarray[5], NULL == strarray[6]);

i get 0 1

kprime21
  • 37
  • 4
  • 2
    reading beyond the size is UB... – ΦXocę 웃 Пepeúpa ツ Aug 23 '21 at 12:55
  • 2
    Trying to access an element outside of the array is undefined behavior. `argv` is a special case, in that a `NULL` pointer is placed after the last pointer, but that `NULL` is part of the `argv` array. In your case, your array has 5 elements, so that's all the space that is allocated for it. The only valid indices are in the range 0-4. Anything else is accessing something outside of the array, and is undefined behavior. – Tom Karzes Aug 23 '21 at 13:01
  • use `char * strarray[] = {"first", "second", "third", "fourth", "fifth", NULL};` if you want the 6th element to be `NULL` – Bodo Aug 23 '21 at 13:02
  • Why do you expect to find specific values in memory that does not belong to your data object? – Gerhardh Aug 23 '21 at 13:02
  • 1
    Whatever you thought you understood about C, that caused you to predict that accessing a nonexistent array element would give you a nice clean `NULL` instead — banish that thought! It is a false and very misleading one! – Steve Summit Aug 23 '21 at 13:03
  • 1
    When you saw that `strarray[6]` was `NULL`, that was random chance; it doesn't prove anything about `strarray[5]`, or `strarray[10]`, or `strarray[-1]`, or anything else. – Steve Summit Aug 23 '21 at 13:41

4 Answers4

4

Accessing uninitialized memory is undefined behavior, you cannot expect your program to work in a predictable manner. Change the compiler, compiler options, OS, and your program may crash instead of working. Do not expect on undefined behavior and always look at all compiler warnings.

Arkadiusz Drabczyk
  • 11,227
  • 2
  • 25
  • 38
  • There is no unitialized memory in the program. It is just memory that does not belong to the data object that is used to access it. – Gerhardh Aug 23 '21 at 12:59
  • 1
    `There is no unitialized memory in the program` - how isn't there? Where is `strarray[6]` initialized? – Arkadiusz Drabczyk Aug 23 '21 at 13:00
  • That element does not exist. That is not the same as not being initialized. – Gerhardh Aug 23 '21 at 13:00
  • 1
    `strarray[6]` is never initialized, but it is not uninitialized memory. In the same way, the variable `foo` is never initialized. – William Pursell Aug 23 '21 at 13:00
  • How would you know whether the variable which happens to be located in memory right behind `strarray[5]` is initialized or not? – Gerhardh Aug 23 '21 at 13:01
  • Asking whether it's proper to say that a nonexistent array element is also "uninitialized" is kind of an abstract philosophical argument. More importantly, though, while there's debate over [whether using an uninitialized object is undefined](https://stackoverflow.com/questions/11962457), accessing a nonexistent one certainly is! – Steve Summit Aug 23 '21 at 13:10
2

You read memory that is not part of the array that you use to access it. That is illegal and causes undefined behaviour.

Just imagine the following variable definitions:

char *msg1 = "Not part of strarray[]!";
char *strarray[] = {"first", "second", "third", "fourth", "fifth"};
char *msg2 = "Also not part of strarray[]!";

Then where would you expect strarray[6] to hold a NULL value? You could hit the content of msg1 or msg2 or something else. That is not defined. But there is no extra storage for an unlimited number of extra elements reserved in memory just in case you ignore array bounds.

Your problem is not related to uninitialized memory but to an illegal out of bounds access to your array.

Gerhardh
  • 11,688
  • 4
  • 17
  • 39
1

value of first element beyond the end of array?

There is no "first element" beyond the end of the array strarray. The memory after the array can contain any garbage.

So in general dereferencing memory beyond an array invokes undefined behavior.

If you want that the last element of an array of pointers would be equal to NULL then explicitly specify that. For example

char * strarray[] = {"first", "second", "third", "fourth", "fifth", NULL };

or

char * strarray[6] = {"first", "second", "third", "fourth", "fifth" };

Also as this is an array of string literals that may not be modified then it is better to declare the array with the qualifier const

const char * strarray[] = {"first", "second", "third", "fourth", "fifth", NULL };
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
1

When you write char foo[] = "abcde";, the compiler counts the characters in "abcde" and uses that to set the array size. There are actually six characters in "abcde" because a string literal in C source code designates an array that contains all the characters in the text of the string literal plus an automatically added null character to mark the end. So, char foo[] = "abcde"; defines an array of six elements, and foo[5] is zero.

When you write char *bar[] = {"first", "second", "third", "fourth", "fifth"};, the compiler counts the initial values you have listed and uses that to set the array size. There are five initial values in the list. Unlike with string literals, nothing automatically adds a null pointer at the end. So this definition defines an array of five elements. bar[5] is not part of the array, and the behavior of accessing it is not defined by the C standard.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312