Passing char array to struct member - c

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.

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);

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.

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.

Related

How to solve the error: assignment to expression with array type

I am asked to create a carinfo structure and a createcarinfo() function in order to make a database. But when trying to allocate memory for the arrays of the brand and model of the car, the terminal points out two errors.
For:
newCar->brand =(char*)malloc(sizeof(char)*(strlen(brand) + 1));
newCar->model = (char*)malloc(sizeof(char)*(strlen(model) + 1));
it says that there is an error: assignment to expression with array type and an arrow pointing to the equal sign.
struct carinfo_t {
char brand[40];
char model[40];
int year;
float value;
};
struct carinfo_t *createCarinfo(char *brand, char *model, int year, float value){
struct carinfo_t *newCar;
newCar=(struct carinfo_t*)malloc( sizeof( struct carinfo_t ) );
if (newCar){
newCar->brand =(char*)malloc(sizeof(char)*(strlen(brand) + 1));
newCar->model = (char*)malloc(sizeof(char)*(strlen(model) + 1));
strcpy(newCar->brand, brand);
strcpy(newCar->model, model);
//newCar->brand=brand;
//newCar->model=model;
newCar->year=year;
newCar->value=value;
}
return newCar;
};
Two things.
In your code, brand and model are already of array type, they have memory allocated to them based on their size (char [40]) on declaration. You need not allocate any memory using the allocator function (unlike pointers, on other hand).
You cannot assign to an array type. Array types are not suitable for a LHS argument for an assignment operator.This is what basically throws the error you see, but if you adhere to #1, you'll never reach here.
You are declaring the fixed size arrays in the struct.
Maybe you want to do this:
struct carinfo_t {
char *brand;
char *model;
int year;
float value;
};
It seems you may have mistyped the definition of your struct.
Maybe change it to something like this:
struct carinfo_t {
char* brand;
char* model;
int year;
float value;
};
The reason you are getting that error is because you are trying to assign the pointer returned by malloc to an array. That won't work. You should instead be storing the pointer returned by malloc in a char*.

Add struct to struct array using void pointer to said array in C

Let's say I have the following struct and array of that struct:
struct Fileinfo {
int ascii[128]; //space to store counts for each ASCII character.
int lnlen; //the longest line’s length
int lnno; //the longest line’s line number.
char* filename; //the file corresponding to the struct.
};
struct Analysis fileinfo_space[8]; //space for info about 8 files
I want to have a function that will add a new struct to this array. It must take a void pointer to the position where to store the struct as an argument
int addentry(void* storagespace){
*(struct Fileinfo *)res = ??? //cast the pointer to struct pointer and put an empty struct there
(struct Fileinfo *)res->lnlen = 1; //change the lnlen value of the struct to 1
}
My questions are:
What goes in place of ??? I tried (Fileinfo){NULL,0,0,NULL} as per this Stackoverflow response. But I get `error: ‘Fileinfo’ undeclared (first use in this function)
How do I create a void pointer to the array? Is (void *)fileinfo_space correct?
I am required to use void * as the argument for the function for this assignment. It's not up to me.
Let's say you have some memory block passed as storagespace void pointer:
You have to define a constant to be able to initialize (unless you're using c++11), let's call it init. BTW your assignment value is wrong: first member is an array of int. You cannot pass NULL to it. Just zero-fill it like show below.
Then cast your void pointer into a pointer on your struct, then initialize by copying the init struct, modify at will...
int addentry(void* storagespace){
static const struct Fileinfo init = {{0},0,0,NULL};
struct Fileinfo *fi = (struct Fileinfo *)storagespace;
*fi = init; //cast the pointer to struct pointer and put an empty struct there
fi->lnlen = 1; //change the lnlen value of the struct to 1
}

Dynamic memory allocation for arrays and strings in struct in C

I want to be create a struct, but I also want to write its array or string elements with dynamic memory allocation.
struct st {
char *name[40];
int age;
};
For "name" string should I use malloc before struct, or can I use it in struct also.
1)
char *name = malloc(sizeof(char)*40);
struct st {
char *name;
int age;
};
2)
struct st {
char *name = malloc(sizeof(char)*40);
int age;
};
Are both of them true or is there any mistake? And if both of them are true, which one is more useful for other parts of code?
You need to create an instance of the structure, an actual variable of it. Then you need to initialize the members of the structure instance in a function.
For example, in some function you could do
struct st instance;
instance.name = malloc(...); // Or use strdup if you have a string ready
instance.age = ...;
An option would be to have a pointer in the struct however allocate memory outside of the struct within the function you use it.
e.g.
struct st {
char* n;
int a;
};
void foo() {
char* name = malloc(sizeof(char) * 40);
int age = 0;
struct st s = (struct st) {
.n = name,
.a = age,
};
/* TO DO */
free(name);
}
Declaring a type does not create lvalues (like variable). It defines the format of the lvalue. In 1), you have correctly declared a struct type, but you seem to have assumed the similarity of the "name" variable in struct declaration will associate the pointer "name" to struct member "name". It does not work that way.
2) is syntactically/symantically wrong. You simply cannot assign a malloc() to non-lvalue (as you are declaring a type struct)
So, create a variable out of struct type as you have created in 1) and allocate memory in the struct variable member.
typedef struct st {
char *name;
int age;
} st_type;
st_type st_var;
st_var.name = (char *) malloc(sizeof(char) * 40); // This is how you will allocate the memory for the struct variable.
Remember, before you can do dynamic allocation, you need to have a lvalue just like you did for standalone "name" variable.

Incompatible types in assignment, Why can't I do this?

I have a struct The_Word that has a variable char word[WORD_LENGTH]
I have the following
typedef struct The_Word
{
char word[WORD_LENGTH];
int frequency;
struct The_Word* next;
} The_Word;
int someFunc(char* word)
{
/*Rest of method excluded*/
struct The_Word *newWord = malloc(sizeof(struct The_Word));
newWord->word = word; // error here. How can I assign the struct's word to the pointer word
}
You need to use strncpy to copy an string:
#include <string.h>
int someFunc(char* word)
{
/*Rest of method excluded*/
struct The_Word *newWord = malloc(sizeof(struct The_Word));
strncpy(newWord->word, word, WORD_LENGTH);
newWord->word[WORD_LENGTH - 1] = '\0';
}
You should be careful to check if the string fits in the array. That's it, when the length of the parameter char* word is longer than WORD_LENGTH.
You don't assign pointers directly. Instead you should use strncpy() function.
strncpy(newWord->word,word,strlen(word));
strcpy(), memcpy() all work similarly.
typedef struct The_Word
{
char word[WORD_LENGTH];
int frequency;
struct The_Word* next;
} The_Word;
int someFunc(char* word)
{
/*Rest of method excluded*/
struct The_Word *newWord = malloc(sizeof(struct The_Word));
memset(newWord->word,0,WORD_LENGTH);
strcpy(newWord->word,word);
/*return something*/
}
This gives an incompatible types error because in C arrays are treated as constant pointers. Arrays and pointers are not exactly the same thing. Although they behave identically in most other circumstances, you cannot reassign what an array points to.
It looks like you intend to copy the string from the function argument into the newly allocated struct. If this is the case use strncpy() or memcpy() as others have suggested.

How to work with string fields in a C struct?

I'm having trouble making a database based on a singly-linked list in C,
not because of the linked list concept but rather the string fields in the struct themselves.
This is an assignment in C and as far as I know (I'm a newbie), C doesn't recognize 'string' as a data type.
This is what my struct code looks like:
typedef struct
{
int number;
string name;
string address;
string birthdate;
char gender;
} patient;
typedef struct llist
{
patient num;
struct llist *next;
} list;
I was thinking of making a struct for the strings themselves so that I can use them in the struct, like this:
typedef struct string
{
char *text;
} *string;
Then I will malloc() each one of them when it is required to make new data of the string type (array of char).
typedef struct string
{
char *text;
} *string;
int main()
{
int length = 50;
string s = (string) malloc(sizeof string);
s->text = (char *) malloc(len * sizeof char);
strcpy(s->text, patient.name->text);
}
Can someone help me figure this out?
Thank you.
On strings and memory allocation:
A string in C is just a sequence of chars, so you can use char * or a char array wherever you want to use a string data type:
typedef struct {
int number;
char *name;
char *address;
char *birthdate;
char gender;
} patient;
Then you need to allocate memory for the structure itself, and for each of the strings:
patient *createPatient(int number, char *name,
char *addr, char *bd, char sex) {
// Allocate memory for the pointers themselves and other elements
// in the struct.
patient *p = malloc(sizeof(struct patient));
p->number = number; // Scalars (int, char, etc) can simply be copied
// Must allocate memory for contents of pointers. Here, strdup()
// creates a new copy of name. Another option:
// p->name = malloc(strlen(name)+1);
// strcpy(p->name, name);
p->name = strdup(name);
p->address = strdup(addr);
p->birthdate = strdup(bd);
p->gender = sex;
return p;
}
If you'll only need a few patients, you can avoid the memory management at the expense of allocating more memory than you really need:
typedef struct {
int number;
char name[50]; // Declaring an array will allocate the specified
char address[200]; // amount of memory when the struct is created,
char birthdate[50]; // but pre-determines the max length and may
char gender; // allocate more than you need.
} patient;
On linked lists:
In general, the purpose of a linked list is to prove quick access to an ordered collection of elements. If your llist contains an element called num (which presumably contains the patient number), you need an additional data structure to hold the actual patients themselves, and you'll need to look up the patient number every time.
Instead, if you declare
typedef struct llist
{
patient *p;
struct llist *next;
} list;
then each element contains a direct pointer to a patient structure, and you can access the data like this:
patient *getPatient(list *patients, int num) {
list *l = patients;
while (l != NULL) {
if (l->p->num == num) {
return l->p;
}
l = l->next;
}
return NULL;
}
I think this solution uses less code and is easy to understand even for newbie.
For string field in struct, you can use pointer and reassigning the string to that pointer will be straightforward and simpler.
Define definition of struct:
typedef struct {
int number;
char *name;
char *address;
char *birthdate;
char gender;
} Patient;
Initialize variable with type of that struct:
Patient patient;
patient.number = 12345;
patient.address = "123/123 some road Rd.";
patient.birthdate = "2020/12/12";
patient.gender = 'M';
It is that simple. Hope this answer helps many developers.
While Richard's is what you want if you do want to go with a typedef, I'd suggest that it's probably not a particularly good idea in this instance, as you lose sight of it being a pointer, while not gaining anything.
If you were treating it a a counted string, or something with additional functionality, that might be different, but I'd really recommend that in this instance, you just get familiar with the 'standard' C string implementation being a 'char *'...
You could just use an even simpler typedef:
typedef char *string;
Then, your malloc would look like a usual malloc:
string s = malloc(maxStringLength);
This does not work:
string s = (string)malloc(sizeof string);
string refers to a pointer, you need the size of the structure itself:
string s = malloc(sizeof (*string));
Note the lack of cast as well (conversion from void* (malloc's return type) is implicitly performed).
Also, in your main, you have a globally delcared patient, but that is uninitialized. Try:
patient.number = 3;
patient.name = "John";
patient.address = "Baker street";
patient.birthdate = "4/15/2012";
patient.gender = 'M';
before you read-access any of its members
Also, strcpy is inherently unsafe as it does not have boundary checking (will copy until the first '\0' is encountered, writing past allocated memory if the source is too long). Use strncpy instead, where you can at least specify the maximum number of characters copied -- read the documentation to ensure you pass the correct value, it is easy to make an off-by-one error.

Resources