-1

Usually, this question is probably phrased in a positive way, becoming the next member in the club of duplicate questions - this one hopefully isn't. I have written a simple program to reverse a string in C. Here it is:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
    char arr[4] = "TEST";
    char rev[2];

    int j = 0;
    for(int i = 0; i < 4; i++) {
        j = 4 - i - 1;
        rev[j] = arr[i]; 
    }

    printf("%s\n",rev);
}

When I define char arr and char rev to be of size 4, everything works fine. When I leave arr size out I get unexpected repeat output like "TSTTST". When I define rev to be an array of 2 chars, I do not get a segfault, yet in the loop I am trying to access its third and fourth element. As far as my relatively limited understanding tells me, accessing the third element in an array of length two should segfault, right? So why doesn't it?

EDIT:

Interestingly enough, when I leave the loop out like so

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
    char arr[4] = "TEST";
    char rev[2] = "00";

    printf("%s\n",rev);
}

it prints "00TEST". What happened here? Some kind of overflow? I even restarted the terminal, recompiled and ran again.

EDIT 2:

I have been made aware that this is indeed a duplicate. However, most of the suggested duplicates referred to C++, which this isn't. I think this is a good question for new C programmers to learn about and understand undefined behavior. I, for one, didn't know that accessing an array out of bounds does not always cause a SEGFAULT. Also, I learned that I have to terminate string literals myself, which I falsely believed was done automatically. This is partly wrong: it is added automatically - the C99 Standard (TC3) says in 6.4.5 String literals that terminating nulls are added in translation phase 7. As per this answer and the answers for this question, char arrays are also null-terminated, but this is only safe if the array has the correct length (string length + 1 for null-terminator).

NXP5Z
  • 173
  • 7
  • 1
    [Why don't I get a segmentation fault when I write beyond the end of an array?](https://stackoverflow.com/q/12410016/995714), [No segmentation fault for accessing out of bound memory](https://stackoverflow.com/q/27730460/995714) – phuclv Sep 20 '20 at 14:06
  • 1
    `%s` will print until `\0`. Which you lack – Tony Tannous Sep 20 '20 at 14:11
  • 2
    About your edit: the `printf` format specifier `%s` expects a null-terminated string. Your "strings" aren't null-terminated so you have yet another variation of undefined behavior. – Blastfurnace Sep 20 '20 at 14:12
  • 1
    dupes in C: [No out of bounds error](https://stackoverflow.com/q/9137157/995714), [C - Off by one error, but no segmentation fault?](https://stackoverflow.com/q/34521292/995714), [Array allows out of bounds access in C? (duplicate)](https://stackoverflow.com/q/38416792/995714) – phuclv Sep 21 '20 at 04:12

1 Answers1

2

char rev[2] assigns a memory of size 2*sizeof(char) with variable/pointer rev. You are accessing memory not allocated to the pointer. It may or may not cause errors.

It might appear to work fine, but it isn't very safe at all. By writing data outside the allocated block of memory you are overwriting some data you shouldn't. This is one of the greatest causes of segfaults and other memory errors, and what you're observing with it appearing to work in this short program is what makes it so difficult to hunt down the root cause.

When you do rev[2] or rev[3] you are accessing rev + 2 and rev + 3 addresses which are not allocated to rev pointer. Since its a small program and there is nothing there, it's not causing any errors.

In respect to edit:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
    char arr[4] = "TEST";
    char rev[2] = "00";

    printf("%s\n",rev);
}

%s prints till null is encountered, the size you have assigned of the arr and rev doesn't allow for null to be there, try changing values as follow:

    char arr[5] = "TEST";
    char rev[3] = "00";

The program will work as intended as in arr there will be TEST\0 and rev will be rev\0 where \0 is null character in C.

Give this article a read, it'll solve most of your queries.

Mohit Sharma
  • 338
  • 2
  • 13