3

This is the following code: Why it is giving segmentation fault when I try to access first value of array? What are all this warnings?

#include<stdio.h>
int main(void)
{
    int *ptr = {1,2,3,4,5};//Is it not similar to char *ptr="Stackoverflow"?
    printf("%d\n",*ptr);// why Segmentation fault(core dumped) instead of 1
    return 0;
}

...
output:

warning: initialization makes pointer from integer without a cast [enabled by default] 
int *ptr = {1,2,3,4,5};
^

warning: (near initialization for ‘ptr’) [enabled by default]
warning: excess elements in scalar initializer [enabled by default]
warning: (near initialization for ‘ptr’) [enabled by default]
warning: excess elements in scalar initializer [enabled by default]
warning: (near initialization for ‘ptr’) [enabled by default]
warning: excess elements in scalar initializer [enabled by default]
warning: (near initialization for ‘ptr’) [enabled by default]
warning: excess elements in scalar initializer [enabled by default]
warning: (near initialization for ‘ptr’) [enabled by default]
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
geetesh singh
  • 49
  • 1
  • 6
  • 1
    `int *ptr = {1,2,3,4,5};` means `int *ptr = (int *)1;`, which makes no sense. (This is GCC extension, it is illegal in standard C.) If you want an array, use `int ptr[] = {1,2,3,4,5};`. – HolyBlackCat Feb 11 '16 at 17:34
  • Possible duplicate of [This Link](http://stackoverflow.com/questions/35266987/int-nums-5-2-1-4-causes-a-segmentation-fault?newsletter=1&nlcode=537056%7c1ced) – Amber Beriwal Feb 19 '16 at 18:32

6 Answers6

5

//Is it not similar to char *ptr="Stackoverflow"?

TL;DR No, it is not.


The used initializer, {1,2,3,4,5} is called a brace-enclosed initalizer which is supposed to initialize the values of the type of the elements. This is used for aggregate or union type type, like mentioned as in C11, chapter §6.7.9, Initialization

the initializer for an object that has aggregate or union type shall be a brace enclosed list of initializers for the elements or named members.

Here, the initializer list contains all int values, and you're trying to initialize a pointer thought it. This is wrong.

Also, regarding the scalar type, quoting C11, chapter §6.2.5

Arithmetic types and pointer types are collectively called scalar types.[...]

and the aggregate types

[...]Array and structure types are collectively called aggregate types.

There are many issues here, like

  1. You're using int value to initialize an int *.
  2. You're ending up supplying a brace enclosed list containing more than one initializer element for a scalar object.

So, later in your code,

 printf("%d\n",*ptr);

is essentially an invalid memory access, which invokes undefined behavior. The segmentation fault is one of the many side-effects.

Coming to the point of the comment,

char *ptr="Stackoverflow"?

In case of char *ptr="Stackoverflow";, here, "Stackoverflow" is called a string literal and ptr is initalized with the base address of the string literal.


Solution:

You need to have an array of ints which you can initialize using the brace-enclosed initializer. Something along the line of

 int ptr[] = {1,2,3,4,5};

will be valid. Then you can use it like

 for(int i = 0; i < 5; i++)
    printf("%d\t", *(ptr+i));
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • I would add that OP's code actually initializes `int *ptr` with value `1`, because it's first in the list. – HolyBlackCat Feb 11 '16 at 17:21
  • 1
    @HolyBlackCat: Only if you ignore the constraint violations of (a) using the `int` value `1` to initialize a pointer, and (b) providing initializers for objects that don't exist. A conforming compiler could (and IMHO should) simply reject the code, meaning that nothing is initialized to anything. There is no language rule that says that if there are too many initializers, the excess ones are ignored. – Keith Thompson Feb 11 '16 at 17:26
  • @KeithThompson Yes, a conforming compiler must reject the code, and this is how gcc with `-pedantic-errors` acts. But without this flag it only emits some warnings and puts `1` into the pointer. (I should have mentioned that I'm talking about gcc behaviour without the flag.) – HolyBlackCat Feb 11 '16 at 17:32
  • @HolyBlackCat: No, a conforming compiler is merely required to issue a diagnostic. The only thing a conforming compiler is actually required to fail to compile is a `#error` directive. – Keith Thompson Feb 11 '16 at 17:58
  • @KeithThompson Oops. Thanks. I learn something new about C++ every day! – HolyBlackCat Feb 11 '16 at 18:48
  • @HolyBlackCat: I was actually referring to rules in the C standard, but I think C++ is similar. – Keith Thompson Feb 11 '16 at 19:12
3

Your original code is invalid. It contains at least two constraint violations: it provides initializers for objects that don't exist, and it tries to use an initializer 1 (of type int) for an int* object. A compiler could (and IMHO should) simply reject it. gcc is being overly permissive by compiling your code after merely warning about the errors. The resulting code has undefined behavior.

const char *cptr = "Hello";

The above is valid. "Hello" is an expression of array type (specifically of type char[6]). In most contexts, including this one, such an expression is implicitly converted to a pointer to the array's 0th element. Note that I've added const so the compiler will at least warn if I attempt to modify the data that cptr points to.

int *iptr = { 1, 2, 3, 4, 5 }; // invalid

This is invalid. You might expect that it's handled similarly to cptr. The problem is that { 1, 2, 3, 4, 5 } is not an expression; it's valid only in an initializer. It could be a valid initializer for an array object, but since it's not an expression, the array-to-pointer conversion rule doesn't apply.

Assuming your compiler supports C99 or later (specifically the compound literal feature), you can write:

int *iptr = (int[]){ 1, 2, 3, 4, 5 };

(This is not a cast; the syntax is similar, but the { ... } is not an expression.)

The compound literal is an expression of array type, specifically int[5], and the array-to-pointer conversion applies.

One caveat: A string literal creates an array object, and that object has static storage duration, meaning that it exists throughout the execution of the program. A compound literal creates an object with static storage duration only if it appears outside any function; inside a function, it creates an object with automatic storage duration, meaning that it ceases to exist when you reach the end of the current block. In this case, it's defined inside the main function, so it's not likely to be an issue. But it's something to watch out for. For example, this is safe:

const char *new_string(void) {
    const char *result = "hello";
    return result;
}

but this is not:

int *new_array(void) {
    int *result = (int[]){ 1, 2, 3, 4, 5 };
    return result; /* BAD! */
}

because the array ceases to exist when you leave the function. To avoid that, you can create the array object explicitly to make it static:

int *new_array(void) {
    static const int arr[] = { 1, 2, 3, 4, 5 };
    int *result = arr; /* or &arr[0] */
    return result;     /* or "return arr;" */
}
Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
0

Pointer is a scalar data type and standard says that (C11-6.7.9):

The initializer for a scalar shall be a single expression, optionally enclosed in braces.

You can't initialize a scalar data type with brace enclosed initializer having more than one expressions.

In case of

char *ptr="Stackoverflow";  

ptr is pointing to the object with type array of char (look at standard C11:§6.7.9/11). It just initializes ptr to the start of the address of string literal.

haccks
  • 104,019
  • 25
  • 176
  • 264
0

try:

#include<stdio.h>
int main(void)
{
    int ptr[] = {1,2,3,4,5};//Is it not similar to char *ptr="Stackoverflow"?
    printf("%d\n",*ptr);// why Segmentation fault(core dumped) instead of 1
    return 0;
}

In the original code:

int *ptr = {1,2,3,4,5};

{1,2,3,4,5} won't initialize an integer array. String initialization is a special case which is not applicable over other types.

So this code will initialize an integer pointer which will point to memoery address 0x00000001 (first one in the initializer block)

This address is out of program scope and thus segmentation error came into picture.

Amber Beriwal
  • 1,568
  • 16
  • 30
  • Yes. An array of int is **not** the same thing (type) as a pointer to int. (Whereas a literal string **is** of type pointer to char.) – Jeff Y Feb 11 '16 at 17:05
  • @JeffY You are commenting on the wrong post. This answer simply copied over the `//` comments from the original question. – dxiv Feb 11 '16 at 17:10
  • 1
    This answer is good, but could be better if it specified *why* this code is good and the original one was bad – anatolyg Feb 11 '16 at 17:11
0

basically that line is invalid, the c compiler has tried to make sense of it but really cannot. You need the syntax here

How to initialize all members of an array to the same value?

Summary

int myArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Community
  • 1
  • 1
pm100
  • 48,078
  • 23
  • 82
  • 145
0

You are trying to store values in an unitialised pointer. The value of the pointer must be attached to a memory location prior you can access it. Just do some malloc before:

int $ptr;
ptr = malloc( 5* sizeof(int)); // since you have 5 values and then you can initialize your data
for (i=0;i<5;i++) {

(*ptr+i) = (i+1);

}
Null
  • 1,950
  • 9
  • 30
  • 33
claudio06
  • 44
  • 3