2016-01-08 40 views
0

我试图用fscanf一个结构中分配一个字符串, 我尝试这样做:如何使用fscanf或fgets动态分配结构中的字符串?

#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,但我的字符串被一个空格分开,所以我需要实现另一个功能,拆分。谁能帮我?

+5

千万不要使用'scanf'函数,它们按设计破坏。你想'fgets' +'strtok' +'strdup'。另外,根据定义,'sizeof(char)'是1 *,所以不要写它。 – zwol

+0

你有任何错误或警告? ?? –

+0

显示输入文件分隔方式的示例将有所帮助。只需几行,如果所有行都包含相同的字段集合。 – ryyker

回答

2
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

一对夫妇的简单建议,以改善:

1)void main (void)真的一个很好的原型main。用途:

int main(void); 

或者:

int main(int argc, char **argv); 

2)没有必要cast the return of [m][c][re]alloc in C
这行代码:

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()作为最小的方法来读取,解析和将文件中的字符串复制到结构成员中:

注意:这里将会有一些电话号码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 
}