“int *nums = {5, 2, 1, 4}” causes a segmentation fault

后端 未结 5 580
情书的邮戳
情书的邮戳 2020-11-29 04:20
int *nums = {5, 2, 1, 4};
printf(\"%d\\n\", nums[0]);

causes a segfault, whereas

int nums[] = {5, 2, 1, 4};
printf(\"%d\\n\", nums[         


        
5条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2020-11-29 04:41

    There is a (stupid) rule in C saying that any plain variable may be initialized with a brace-enclosed initializer list, just as if it was an array.

    For example you can write int x = {0};, which is completely equivalent to int x = 0;.

    So when you write int *nums = {5, 2, 1, 4}; you are actually giving an initializer list to a single pointer variable. However, it is just one single variable so it will only get assigned the first value 5, the rest of the list is ignored (actually I don't think that code with excess initializers should even compile with a strict compiler) - it does not get written to memory at all. The code is equivalent to int *nums = 5;. Which means, numsshould point at address 5.

    At this point you should already have gotten two compiler warnings/errors:

    • Assigning integer to pointer without a cast.
    • Excess elements in initializer list.

    And then of course the code will crash and burn since 5 is most likely not a valid address you are allowed to dereference with nums[0].

    As a side note, you should printf pointer addresses with the %p specifier or otherwise you are invoking undefined behavior.


    I'm not quite sure what you are trying to do here, but if you want to set a pointer to point at an array, you should do:

    int nums[] = {5, 2, 1, 4};
    int* ptr = nums;
    
    // or equivalent:
    int* ptr = (int[]){5, 2, 1, 4};
    

    Or if you want to create an array of pointers:

    int* ptr[] = { /* whatever makes sense here */ };
    

    EDIT

    After some research I can say that the "excess elements initializer list" is indeed not valid C - it is a GCC extension.

    The standard 6.7.9 Initialization says (emphasis mine):

    2 No initializer shall attempt to provide a value for an object not contained within the entity being initialized.

    /--/

    11 The initializer for a scalar shall be a single expression, optionally enclosed in braces. The initial value of the object is that of the expression (after conversion); the same type constraints and conversions as for simple assignment apply, taking the type of the scalar to be the unqualified version of its declared type.

    "Scalar type" is a standard term referring to single variables that are not of array, struct or union type (those are called "aggregate type").

    So in plain English the standard says: "when you initialize a variable, feel free to toss in some extra braces around the initializer expression, just because you can."

提交回复
热议问题