0

I am trying to learn C, as a hobby. Therefore I am creating a long .c file with lots and lots of declaration, etc to see and learn the programming language. My issue is that my program crashes and I am unable to understand why! Here is the code

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


int main() {
    printf("Hello, World!\n");

    double Double_Array[5] = {[0] = 9.0, [2] = 5.0, [1] = 7.12, [4] = 3.E+25};
    double DoubleArray[] = {0.0007, 0.1, 6};

    for(size_t i = 0; i < 5; i++) {
        // %zu and %g are what's called "format specifiers"
        printf("element␣%zu␣is␣%g,␣\tits␣square␣is␣%g\n", i, Double_Array[i], Double_Array[i]*Double_Array[i]);
    }

    int int_x[] = {1,2,3}; // x has type int[3] and holds 1,2,3
    int int_y[5] = {1,2,3}; // y has type int[5] and holds 1,2,3,0,0
    int int_z[3] = {0}; // z has type int[3] and holds all zeroes

    char str_array[] = "abc"; // str has type char[4] and holds 'a', 'b'. 'c', '\0'
    char str_array3[3] = "abc"; // str has type char[3] and holds 'a', 'b', 'c'
    wchar_t wstr[4] = L"猫"; // str has type wchar_t[4] and holds L'猫', '\0', '\0', '\0'

    // Ternary (condition) operation
    int aaa = 10, bbb = 11;
    (aaa > bbb) ? (printf("A is the biggest!\n")) : (printf("B is the biggest!\n"));

    int my_single_array[5] = {1, 5, 2, 4, 7};
    int my_multidimensional_array[2][3][4] = {
            {{9, 1, 8, 3}, {1, 8, 3, 4}, {8, 3, 4, 5}}, // 0
            {{8, 4, 8, 3}, {8, 5, 5, 1}, {9, 6, 8, 3}} // 1
    }; // 3D

    /*
    for(int i = 0; i < 2; i++) {
        printf("%i\n", my_multidimensional_array[i][i][i]);
    }

    printf("\nsingle array: %i", my_single_array[1239]);
    */
    char* char_A = "A";
    const char* char_AA[2] = {"AA"};
    char* const char_AAA[50] = {"AAA"};
    const char* const char_AAAA[50] = {"AAAA"};

    printf("\n\n"
           "char_A: %s\n"
           "char_AA: %s\n"
           "char_AAA: %s\n"
           "char_AAAA: %s\n"
           " \n\n"
           , char_A,char_AA[0], char_AAA[0], char_AAAA[0]);

    printf("got here"); // never prints this CRASHES BEFORE THIS

    char_A[0] = 'B';
    char_AA[0] = "CD";
    // char_AAA = 'Changed char_AAA'; // ILLEGAL, reason: constant content, movable pointer
    // char_AAAA = 'Changed char_AAAA'; // ILLEGAL, reason: constant content and pointer!

    printf("HERE");
}

Why do I get a segmentation fault error? Am I accessing parts of memory I am not suppost to? I have tried not printing out char_A, char_AA, char_AAA and char_AAAA but the program still crashes after the print despite not accessing the variables.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • This might be interesting to you: https://ericlippert.com/2014/03/05/how-to-debug-small-programs/ – mkrieger1 Jan 26 '20 at 11:06
  • Then make the program smaller, removing "lots of things" until you find the error. As part of learning, you might also use a debugger to find the error. debugging is an important part of learning to program. – Paul Ogilvie Jan 26 '20 at 11:07
  • If you use debug printing, make sure that you print a new line after each statement. Otherwise, the printing may be delayed. (Your `"got here"` might well have been executed, but not been printed yet, because `stdout` is buffered.) – M Oehm Jan 26 '20 at 11:09
  • That said, I suspect that the offending line is the one after the `printf` where you try to change the first character of a string literal. Even if you did not mark it as `const`, `char_A` and the element of `char_AA`are a read-only strings. – M Oehm Jan 26 '20 at 11:11
  • `char* char_A = "A"` ... char_A maps "A" that is in constants area; accessing it a segmentation fault is issued. "A" is a constant! When you (line 57) try to assign `char_A[0]="B"` a segmantation is issued. – Sir Jo Black Jan 26 '20 at 11:12
  • It does not crash when I delete the multiline printf AND the declaration of the char_A, char_AA, and so on. It seems as if declaring those character arrays breaks the brokan. Any idea why the crash is (1) delayed and (2) happens? – Tom Holland Jan 26 '20 at 11:13
  • The issue is the line 57. You CANNOT use `char_A[0]="B"`. Because char_A maps constants area! – Sir Jo Black Jan 26 '20 at 11:16

3 Answers3

0

String literals are immutable in C though opposite to C++ they have types of non-constant character arrays. Any attempt to modify a string literal results in undefined behavior.

char* char_A = "A";
//...
char_A[0] = 'B';

From the C Standard (6.4.5 String literals)

7 It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • IMHO It'is not the completely correct replay. The problem is that "A" is a constant. If you compile, without considering the warning ;), this code: `const int i=100; int main(void) {int * ci; ci=&i; *ci=110;return 0;}` a segmentation will be issued. – Sir Jo Black Jan 26 '20 at 11:28
  • 1
    @SirJoBlack String literals in C have types of non-constant character arrays. Nevertheless you may not modify a string literal. – Vlad from Moscow Jan 26 '20 at 11:29
  • The execution gives segmentation cause the "string literal" is mapped in constants area. If you modify a string literals in a DOS environment you doesn't obtain a segmentation. – Sir Jo Black Jan 26 '20 at 11:31
  • 3
    @SirJoBlack Please read at last the quote I provided from the C Standard. There is nothing wrong in my answer. – Vlad from Moscow Jan 26 '20 at 11:32
  • I know what's the standard says. But what I'm underlining is that the problem is the attempt to write in a read-only memory area. – Sir Jo Black Jan 26 '20 at 11:33
  • @SirJoBlack You are totally wrong. The C Standard does not say where string literals are stored. It is implementation details that have nothing common with the C Standard. If I am not mistaken then for example in DOS you could physically change a string literal. – Vlad from Moscow Jan 26 '20 at 11:35
  • Think as you want ... The standard doesn't know the CPU and/or SO architecture, than cannot talk about segmentation ... ;) – Sir Jo Black Jan 26 '20 at 11:41
  • Furthermore the compiler compiles that code ... ;) – Sir Jo Black Jan 26 '20 at 11:41
  • @SirJoBlack The only sound thought in your comment is that indeed the C Standard does not know any CPU architecture and we are discussing the question from the C Standard point of view. – Vlad from Moscow Jan 26 '20 at 11:43
  • @SirJoBlack The compiler can compile any code. But it does not mean that the code has no undefined behavior.:) – Vlad from Moscow Jan 26 '20 at 11:44
  • I explained the segmentation fault, not the standard. The standard says, but the compiler doesn't signal an error!!! – Sir Jo Black Jan 26 '20 at 11:44
  • 1
    @SirJoBlack As I said a code can have undefined behavior but provides the expected result.:) Each programmer shall know what the Standard says. – Vlad from Moscow Jan 26 '20 at 11:45
  • There's not UB in SO that doesn't generate segmentation. – Sir Jo Black Jan 26 '20 at 11:45
  • @SirJoBlack Again you are wrong. For example read the C++ Standard where you can find any situations of undefined behavior which the compiler can not to determine and there is no any segmentation.:) – Vlad from Moscow Jan 26 '20 at 11:47
  • I agree that's there's a standard. But It's better to know what's the cause of an error. I agree that the standard must be respeceted. But the cause is not the standard in this case. – Sir Jo Black Jan 26 '20 at 11:47
  • This is C not C++. – Sir Jo Black Jan 26 '20 at 11:47
  • 2
    @SirJoBlack It does not matter relative to this aspect.:) – Vlad from Moscow Jan 26 '20 at 11:48
0

The problem is with the declaration of

char* char_A = "A";

This will make char_A constant string, segmentation fault happens when you try to modify it.

Change it to

char char_A[] = "A";
0

I will answer my own questions based on your answers because no one answer is complete.

Defining a string literal as such

char* char_A = "A";

results in an immutable (immutable = constant = not able to change) string literal.

The reason my printf("got here"); never prints is because it is placed in a queue to be printed and then I try to change the constant string literal by doing char_A[0] = 'B';. This results in undefined behaviour (in this case segmentation fault, meaning parts of the memory was altered or tried to be altered which results in a crash).

By either removing char_A[0] = 'B'; or changing char* char_A = "A"; to char char_A[] = "A"; the issue is resolved! Look below for example

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


int main() {
    //char* char_A = "A"; // COMMENTED OUT
    char char_A[] = "A"; // NEW
    const char* char_AA[2] = {"AA"};
    char* const char_AAA[50] = {"AAA"};
    const char* const char_AAAA[50] = {"AAAA"};

    printf("\n\n"
           "char_A: %s\n"
           "char_AA: %s\n"
           "char_AAA: %s\n"
           "char_AAAA: %s\n"
           " \n\n"
           , char_A,char_AA[0], char_AAA[0], char_AAAA[0]);

    printf("got here");

    //char_A[0] = 'B'; // COMMENTED OUT
    char_AA[0] = "CD";
    // char_AAA = 'Changed char_AAA'; // ILLEGAL, reason: constant content, movable pointer
    // char_AAAA = 'Changed char_AAAA'; // ILLEGAL, reason: constant content and pointer!

    printf("HERE");
}