There is typo in your code: the first type should be Value
, not Person
:
typedef struct {
char *Name;
char *Email;
} Value;
typedef struct {
unsigned int len;
Value *pVal;
} Person;
To allocate a structure from the heap, you can use malloc()
an provide the size in bytes of the object to allocate:
Person *p = malloc(sizeof(Person));
Note that you can get the appropriate size from the pointer type, so you can use a more general syntax for all types:
Person *p = malloc(sizeof(*p));
The pVal
pointer seems to point to an array of Value
structures, so your allocation is correct, but the len
member must be initialized to the appropriate number of elements. You can also write:
p->len = count;
p->pVal = malloc(p->len * sizeof(*p->pVal));
Block of memory allocated by malloc()
are not initialized, so you must either initialize all member manually to the appropriate values or use calloc()
that returns a block of memory initialized to all bits zero, which on all modern systems means all members are initialized to their 0 value: integer members to 0
, floating point members to 0.0
and pointers to NULL
:
p->len = count;
p->pVal = calloc(p->len, sizeof(*p->pVal)); // members Name and Email are set to NULL
Note also that the C Standard does not specify if an allocation request for 0 bytes will return a null pointer or a pointer to an object with a zero size. You should avoid trying to allocate zero bytes:
p->len = count;
if (p->len == 0) {
p->pVal = NULL;
} else {
p->pVal = calloc(p->len, sizeof(*p->pVal)); // members Name and Email are set to NULL
}
Note also that any allocation attempt can fail and return a null pointer, so you should test the return value and handle allocation failures gracefully.
For the variable sized strings, you can read the file with fgets()
and use strdup()
to allocate copies of the strings:
char Name[100];
char Email[100];
if (fgets(Name, sizeof Name, fp) != NULL &&
fgets(Email, sizeof Email, fp) != NULL) {
Name[strcspn(Name, "\n")] = '\0'; // strip the trailing newline
Email[strcspn(Email, "\n")] = '\0'; // strip the trailing newline
p->pVal->Name = strdup(Name);
p->pVal->Email = strdup(Email);
} else {
/* handle invalid input */
}
Here is a function that combines the above to read a record from the file:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char *Name;
char *Email;
} Value;
typedef struct {
unsigned int len;
Value *pVal;
} Person;
Person *read_person(FILE *fp, int count) {
Person *p = malloc(sizeof(*p));
if (p == NULL)
return NULL;
p->len = count;
if (p->len == 0) {
p->pVal = NULL;
} else {
p->pVal = calloc(p->len, sizeof(*p->pVal)); // members Name and Email are set to NULL
if (p->pVal == NULL) {
free(p);
return NULL;
}
for (unsigned int i = 0; i < len; i++) {
char Name[100];
char Email[100];
if (fgets(Name, sizeof Name, fp) != NULL &&
fgets(Email, sizeof Email, fp) != NULL) {
Name[strcspn(Name, "\n")] = '\0'; // strip the trailing newline
Email[strcspn(Email, "\n")] = '\0'; // strip the trailing newline
p->pVal[i].Name = strdup(Name);
p->pVal[i].Email = strdup(Email);
} else {
/* handle invalid input */
while (i-- > 0) {
free(p->pVal[i].Name);
free(p->pVal[i].Email);
}
free(p->pVal);
free(p);
return NULL;
}
}
}
return p;
}