hexinpeter
hexinpeter

Reputation: 1570

Array in C struct, pointer to constant

I have the following code:

typedef struct{
    char *name;
    int age;
} person;


int main(){
    person Peter = {"peter", 19};
    person Petercp = Peter;
    Peter.name[0] = 'a';
    Petercp.name = "hello";
    printf("%s %d\n", Peter.name, Peter.age);
    printf("%s %d\n", Petercp.name, Petercp.age);
}

the compiler gives me the error message of "BAD ACCESS" for the line

Peter.name[0] = 'a'

but the following line seems good

Petercp.name = "hello";

It seems as if the array of person.name is a pointer to constant. Am I right to make the conclusion?

And, if I declare the array inside the struct to be

char name[];

I am again allowed to make the change for

Peter.name[0] = 'a'

Why is that?

Upvotes: 0

Views: 145

Answers (3)

nos
nos

Reputation: 229108

When you do person Peter = {"peter", 19};, you point name to a string literal "peter".

Peter.name[0] = 'a' tries to change the 1. element in what name is pointing to. Modifying a string literal is undefined behavior and in your case it causes a crash. In practice string literals are often loaded in a read only section of memory.

On the other hand doing Petercp.name = "hello"; just changes the pointer to point somewhere else, which is fine.

If you declare the name member as char name[64] then the initializer

  person Peter = {"peter", 19};

will copy the string "peter" into the name array. The name array is just an ordinary char array where you can change the individual elements.

Upvotes: 4

Oliver Matthews
Oliver Matthews

Reputation: 7823

Because you haven't declared any space for peter, so Peter.name[0] doesn't exist.

When you do the initial assignment using a constant string the compiler is assigning the constant string value to that, and you can't change constants.

The following would work:

int main(){
    person Peter;
    Peter.age = 19;
    Peter.name = calloc(sizeof(*(Peter.name)),sizeof("hello")+1);
    strncpy(Peter.name,"hello",sizeof("hello"));
    Peter.name[0] = 'a';
    printf("%s %d\n", Peter.name, Peter.age);
    free(Peter.name);
}

The difference here is that a straight Peter.name = "hello" make Peter.name point directly to the (const) string literal. strncpy by comparison will copy from that literal to the space put aside by the calloc

Upvotes: 0

dhein
dhein

Reputation: 6555

Assigning a name by "NAME" creates a string literal which is defined as constant. So you aren't allowed to change anything on the address, where name is pointing to.

Its in c11 under 6.7.3

If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined. If an attempt is made to refer to an object defined with a volatile-qualified type through use of an lvalue with non-volatile-qualified type, the behavior is undefined.

Peter.name[0] = 'a'

And thats exactly what your trying to do in this line.

So you would break your code. But the compiler fortunately avoids this.

Upvotes: 0

Related Questions