[英]How to Dynamically Allocate a string within a struct with fscanf or fgets?
我正在尝试使用fscanf
在结构中分配字符串,我尝试了以下方法:
#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;
}
也许在我的脑海中是正确的,但是在加载数据时出了点问题,所以这是动态读取字符串的正确而清晰的方法吗? 我以为使用fgets
,但是我的字符串用空格隔开,所以我需要实现另一个功能,即split。 谁能帮我?
while((k=fscanf(f,"%s %s %s %s",s[0],s[1],s[2],s[3]))==4) {
//your code
i++;
}
而不是使用fgets
读取完整的数据,然后使用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++;
}
可以使用它代替循环。
注意 - 请勿这样做 -
Archive[i].id = (char*) malloc( sizeof(char) *(strlen(s[0])+1));
Archive[i].id =s[0]; <-- 2.
与2.
语句之后一样,您将失去对先前分配的内存的引用,并且将无法free
它-导致内存泄漏。
对于以下所有此类语句,都是相同的。
有几个快速建议可以改进:
1) void main(void)确实不是 main
的良好原型。 采用:
int main(void);
要么:
int main(int argc, char **argv);
2)无需在C中强制转换[m] [c] [re] alloc的返回值 。
您代码中的这一行:
Archive[i].id = (char*) malloc( sizeof(char) *strlen(s[0]));
^^^^^^^ ^^^^^^^^^^^^^^ //^^^ == remove
应该写成:
Archive[i].id = malloc( strlen(s[0]) + 1);//no cast, and sizeof(char) is always == 1
//"+ 1" for NULL termination
3)建议使用fgets() , strtok()和strcpy()作为从文件读取,解析和复制字符串到struct成员的最小方法:
注意:这里将有许多对
malloc()
的调用,每个调用都必须在某个时候释放。 为了避免所有这些,最好是您的结构包含具有硬编码堆栈内存的成员:
typedef struct
{
char name[80];
char surname[80];
char id[80];
char telephone[80];
}SPerson;
但是,假设您有使用堆内存的理由,这是一种使用定义的结构来进行处理的方法:
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
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.