tags:

views:

2281

answers:

3

I have the following structure:

struct hashItem {
    char userid[8];
    char name[30];
    struct hashItem *next;
};

In the function below I take a char pointer (char array) argument that I wish to assign to the struct.

void insertItem(struct hashItem *htable[], char *userid, char *name)
{
    int hcode = hashCode(userid);
    struct hashItem *current = htable[hcode];

    struct hashItem *newItem = (struct hashItem*) malloc(sizeof(struct hashItem));
    newItem->userid = userid;
    newItem->name = name;
    [...]
}

Instead I get the following error:

hashtable.c: In function ‘insertItem’:
hashtable.c:62: error: incompatible types in assignment
hashtable.c:63: error: incompatible types in assignment

Line 62 and 63 are the `newItem->..." lines.

+2  A: 

You almost certainly don't want to just assign the char* to the char[] - as the compiler points out, the types are incompatible, and the semantics are not what you think. I assume you want the struct members to contain the values of the two char* strings - in which case, you want to call strncpy.

strncpy(target, source, max_chars);
Adam Wright
Suppose I someplace else in my code is sure that the char array is less than the given 8/30 bytes long, how would I assign it directly and not copy it?
Christian P.
In that case, you'd use a char* in the structure, and just copy the pointer across. A char* is just a pointer to some memory containing chars. A char[] is a fixed length storage allocation for n characters. You can't assign between them in a sensible fashion.
Adam Wright
@Christian: making sure of the length has nothing to do with whether you assign or copy. You cannot assign to an array in C, ever. The language doesn't allow it. You have to decide whether you want the new hashItem to contain a copy of the string passed to insertItem (in which case use some kind of copy, together with some kind of bounds checking), or a pointer to it (in which case use a char* instead of a char[] in the struct).
Steve Jessop
A: 

You can't assign a pointer to a string to a character array like you are trying to. Instead you need to copy the contents of the string with strncpy as Adam indicated:

strncpy (newItem->userid, userid, 8);

When you declare the struct with a character array in it, you are allocating memory inside the structure itself to store a string of the given length.

When you pass a pointer into your function, you are passing a memory address (an integer) that indicates where a null-terminated string can be found.

To assign the pointer to the array doesn't make sense. The array has memory allocated for it already -- it can't be made to "point" to another location.

While you can use pointers in your structure, you need to be very careful that when you assign them, you are telling them to point to something that is going to be valid for the duration of the time you will use the structure. For example, this code is bad, because the string passed to insertItem no longer exists after fillStructure returns:

struct hashItem
{
   char * userid;
};

void insertItem (struct hashItem * item, char * userid)
{
   item->userid = userid;
}

void fillStructure (struct hashItem * item)
{
   const char string[] = "testing";
   insertItem (item, string);
}

int main(void)
{
   struct hashItem item;
   fillStructure (&item);
   /* item->userid is now a dangling pointer! */
}

For more, I would recommend reading the "Arrays and Pointers" chapter of the C FAQ -- start with Question 6.2 and keep reading from there.

Nick Meyer
Insert usual argument about strncpy here: if the userid passed in is exactly 8 characters long, then this code will result in the stored string not being nul terminated. That may not be what you want.
Steve Jessop
A: 

You should chang your struct in

struct hashItem {
  char userid[8];
  char *name;
  struct hashItem *next;
};

to assign a char pointer to a name. In the struct you defined char name[30] are just 30 chars.

Eineki
Assuming of course that the caller of insertItem is going to guarantee that the name string will remain valid for the lifetime of the hashItem object.
Steve Jessop