I'm trying to allocate a string within a struct with fscanf
, I tried this:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <Windows.h>
#include <string.h>
typedef struct _SPerson {
char *name;
char *surname;
char *id;
char *telephone;
}SPerson;
void main (void) {
unsigned int ne;
SPerson Archive[1000];
Load(Archive,&ne);
}
int Load(SPerson Archive[],unsigned int *ne) {
int k,i=0;
char s[4][20];
FILE *f;
f = fopen("archive.txt","r");
if(f==0) return 0;
while((k=fscanf(f,"%s %s %s %s",s[0],s[1],s[2],s[3]))==4) {
Archive[i].id = (char*) malloc( sizeof(char) *strlen(s[0]));
Archive[i].id =s[0];
Archive[i].name = (char*) malloc( sizeof(char) *strlen(s[1]));
Archive[i].name = s[1];
Archive[i].surname = (char*) malloc( sizeof(char) *strlen(s[2]));
Archive[i].surname = s[2];
Archive[i].telephone = (char*) malloc( sizeof(char) *strlen(s[3]));
Archive[i].telephone =s[3];
i++;
}
*ne = i;
fclose(f);
return 1;
}
Maybe in my brain it's correct, but something went wrong while loading the data, so is this the correct and clear method to read strings dynamically? I thought to use fgets
, but my string is separated by a space, so I need to implement another function, the split. Can Anyone help me?
while((k=fscanf(f,"%s %s %s %s",s[0],s[1],s[2],s[3]))==4) {
//your code
i++;
}
Instead of this use fgets
to read complete data and then tokenize it using strtok
-
char data[1024],*token;
int j=0;
while(fgets(data,sizeof data,f)!=NULL){ //read from file
token=strtok(data," "); //tokenize data using space as delimiter
while(token!=NULL && j<4){
j=0;
sprintf(s[j],"%s",token); //store it into s[i]
j++;
token=strtok(NULL," ");
}
Archive[i].id = malloc(sizeof *Archive[i].id * (strlen(s[0])+1)); //allocate memory
strcpy(Archive[i].id,s[i]); //copy at that allocated memory
//similar for all
i++;
}
This can be used instead of your loop.
Note - Do not do this -
Archive[i].id = (char*) malloc( sizeof(char) *(strlen(s[0])+1));
Archive[i].id =s[0]; <-- 2.
As after 2.
statement you will lose reference to previous allocated memory and will not be able to free
it — causing a memory leak.
This is same for all such following statements.
A couple of quick suggestions to improve:
1) void main (void) is really not a good prototype for main
. Use:
int main(void);
Or:
int main(int argc, char **argv);
2) There is no need to cast the return of [m][c][re]alloc in C .
This line in your code:
Archive[i].id = (char*) malloc( sizeof(char) *strlen(s[0]));
^^^^^^^ ^^^^^^^^^^^^^^ //^^^ == remove
Should be written:
Archive[i].id = malloc( strlen(s[0]) + 1);//no cast, and sizeof(char) is always == 1
//"+ 1" for NULL termination
3) Suggest using fgets() , strtok() and strcpy() as a minimal method to read, parse and copy strings from file into struct members:
Note: there will be a number of calls to
malloc()
here, and each will have to be freed at some point. To avoid all that, it would be better if your struct contained members with hard coded stack memory:
typedef struct
{
char name[80];
char surname[80];
char id[80];
char telephone[80];
}SPerson;
But assuming you have a reason to use heap memory, here is a way to do it using the struct as you have defined it:
char line[260];//line buffer (hardcoded length for quick demo)
char *tok={0};//for use with strtok()
int len = 0;//for use with strlen()
FILE *f;
f = fopen("archive.txt","r");//did not have example file for this demo
//therefore do not have delimiters, will guess
if(f==0) return 0;
i = 0;//initialize your index
while(fgets(line, 260, f))
{
tok = strtok(line, " ,\n\t");// will tokenize on space, newline, tab and comma
if(tok)
{
len = strlen(tok);
Archive[i].id = malloc(len + 1);//include space for NULL termination
strcpy(Archive[i].id, tok);//note correct way to assign string
//(Archive[i].id = tok is incorrect!!)
}
else {//handle error, free memory and return}
tok = strtok(NULL, " ,\n\t");//note NULL in first arg this time
if(tok)
{
len = strlen(tok);
Archive[i].name= malloc(len + 1);//include space for NULL termination
strcpy(Archive[i].name, tok);
}
else {//handle error, free memory and return}
//...And so on for rest of member assignments
//
i++;//increment index at bottom of while loop just before reading new line
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.