tags:

views:

855

answers:

5

Hi!

I tried to find out what a struct really 'is' and hit a problem, so I have really 2 questions:

1) What is saved in 'sara'? Is it a pointer to the first element of the struct?

2) The more interesting question: Why doesn't it compile? GCC says "test.c:10: error: incompatible types in assignment" and I can't figure out why... (This part has been solved by your answers already, great!)

#include <stdio.h>

struct name {
    char first[20];
    char last[20];
};

int main() {
    struct name sara;
    sara.first = "Sara";
    sara.last = "Black";
    printf("struct direct: %x\n",sara);

    printf("struct deref: %x\t%s\n", *sara, *sara);


}

Thanks for your help!

+3  A: 

This has nothing to do with structs - arrays in C are not assignable:

char a[20];
a = "foo";   // error

you need to use strcpy:

strcpy( a, "foo" );

or in your code:

strcpy( sara.first, "Sara" );
anon
+1 For `strcpy` over `strncpy`... :)
GMan
I would have used char* first; sara.first = "Sara", since I used fixed size arrays only when it's really required; Is it a good or bad practice (in C, not C++)?
gramm
@gramm If you do that, you are committing yourself to dynamic memory management, which may not be necessary or desirable.
anon
+2  A: 

use strncpy to make sure you have no buffer overflow.

char name[]= "whatever_you_want";
strncpy( sara.first, name, sizeof(sara.first)-1 );
sara.first[sizeof(sara.first)-1] = 0;
TimW
This assumes that silently truncating the data doesn't cause your program to fail somewhere else down the line. It's usually better to explicitly handle the case where the string doesn't fit in the buffer, than either to invoke undefined behaviour with strcpy, or put your program in an unexpected state with strncpy. But I generalise - if the rest of your program accounts for silent truncation (e.g. never expects that sara.first will match "whatever_you_want") then the program state is not unexpected.
Steve Jessop
@onebyone this behavior must be documented in the contract.
TimW
If that's sufficient, then why not just document that the input string must be no longer than the struct can cope with? The problem is one of designing APIs which help clients avoid errors. IMO, silently ignoring what is probably an error does not do this. But as I say, I'm generalising, and it might not be an error. If the function is called "StoreFirst20CharsOf", then we can reasonably assume that anyone glancing at the calling code will understand what it does. So there are a few uses for strncpy.
Steve Jessop
StoreFirst20CharsOf is definitely the way to do it ...
TimW
+2  A: 

sara is the struct itself, not a pointer (i.e. the variable representing location on the stack where actual struct data is stored). Therefore, *sara is meaningless and won't compile.

Pavel Minaev
ah, ok... Thanks
Patrick
A: 

The Sara structure is a memory block containing the variables inside. There is nearly no difference between a classic declarations :

char first[20];
int age;

and a structure :

struct Person{
char first[20];
int age;
};

In both case, you are just allocating some memory to store variables, and in both case there will be 20+4 bytes reserved. In your case, Sara is just a memory block of 2x20 bytes.

The only difference is that with a structure, the memory is allocated as a single block, so if you take the starting address of Sara and jump 20 bytes, you'll find the "last" variable. This can be useful sometimes.

check http://publications.gbdirect.co.uk/c_book/chapter6/structures.html for more :) .

gramm
Sara is a memory block of *at least* 2 * 20 bytes. It might be more, if there's padding.
caf
And `offsetof(struct name, last)` is not necessarily 20, either (although it almost certainly is).
caf
Didn't know that. Is there a possibility of padding when specifying variable size ? For example, unsigned char speed : 7 ; unsigned char flags : 3; etc ... I'm using this at work and never had a problem with padding and data alignement.
gramm
If the bitfield follows a non-bitfield member, then there can be padding *before* it. There isn't allowed to be padding *between* two adjacent bitfields, unless they don't fit into the same "basic storage unit" that's being used to hold them (eg. if your implementation uses 8-bit chars to hold bitfields, then it may start a whole new char for `flags`, leaving one bit unused in the char holding `speed`). It's also left defined whether bitfields get allocated left-to-right or right-to-left in the underlying type.
caf
+1  A: 

You can also initialise it like this:

struct name sara = { "Sara", "Black" };

Since (as a special case) you're allowed to initialise char arrays from string constants.

Now, as for what a struct actually is - it's a compound type composed of other values. What sara actually looks like in memory is a block of 20 consecutive char values (which can be referred to using sara.first, followed by 0 or more padding bytes, followed by another block of 20 consecutive char values (which can be referred to using sara.last). All other instances of the struct name type are laid out in the same way.

In this case, it is very unlikely that there is any padding, so a struct name is just a block of 40 characters, for which you have a name for the first 20 and the last 20.

You can find out how big a block of memory a struct name takes using sizeof(struct name), and you can find out where within that block of memory each member of the structure is placed at using offsetof(struct name, first) and offsetof(struct name, last).

caf