我有一个可能很愚蠢的问题......但是我已经定义了一个带有一些char *的结构。 现在当我尝试改变那些字符的值时。 它在编译时没有出现问题,但是当我执行它时,程序就会停止。
这是我用来检查问题所在的测试功能:
struct myret {
int age;
char *name;
char *affiliation_number;
};
void obtain_name_affiliation_number(struct myret *r)
{
int age;
char *name;
char *affiliation_number;
FILE *user_data;
user_data = fopen("user_data.txt", "r");
fscanf(user_data, "%d", &age);
fscanf(user_data, "%s", &name);
fscanf(user_data, "%s", &affiliation_number);
fclose(user_data);
r->age = age;
r->name = name;
r->affiliation_number = affiliation_number;
return 0;
}
int main(void)
{
struct myret r;
int rc = obtain_name_affiliation_number(&r);
if (rc == 0) {
printf("%d %s %s\n", r.age, r.name, r.affiliation_number);
}
getchar();
return 0;
}
感谢一切=)
答案 0 :(得分:2)
您无需使用&
来传递char *
的地址,请删除&
:
fscanf(user_data, "%s", &name);
^
fscanf(user_data, "%s", &affiliation_number);
^
此外,在name
使用affiliation_number
之前为malloc
和char *name = malloc(100 * sizeof(char));
分配内存,例如:
{{1}}
答案 1 :(得分:2)
只是声明char *
没有为它分配任何内存。您需要指定静态大小(例如char name[100]
)或需要动态分配内存(例如,使用malloc
)。如果在完成后使用free
,请记住malloc
内存。
另一个问题是在&
中使用fscanf
char *
。格式字符串后面的scanf
和fscanf
中的变量列表是放置输入值的指针列表。当我们使用类似int age
的类型时,我们需要传递&age
,因为&
之前age
使其成为age
的指针,即int *
}。但是char *name
已经是一个指针,所以这里不需要&
。通过使用&name
,您将创建一个指针或char **
指针,这是您不想要的。
答案 2 :(得分:1)
您只为name和affiliation_number的缓冲区地址分配了空间,但从未为这些地址分配缓冲区本身。
因此,当您在fscanf()
中使用它们时,会出现问题。编译器警告你(gcc,无论如何)这些注释指针是错误的类型 - 它们应该是你希望fscanf
覆盖的目标缓冲区中第一个字节的地址:
foo.c:19:5: warning: format ‘%s’ expects argument of type ‘char *’, but argument 3 has type ‘char **’ [-Wformat]
foo.c:20:5: warning: format ‘%s’ expects argument of type ‘char *’, but argument 3 has type ‘char **’ [-Wformat]
以下是一些事情要做 - 如果您的系统不支持fscanf的"%ms"
规范,请尝试以下操作:
char buffer[1024]
以将数据读入。buffer
或&buffer[0]
(对于某些纯粹主义者)作为字符串fscanfs中的目标%1023s
等来阻止数据读取超出缓冲区的长度 - 超支可能会导致程序疯狂。strdup
将数据克隆到name
或{{1} }。这将affiliation_number
一个新的内存块,其大小适合您读取的字符串并将数据复制到其中。无论您使用这些步骤还是malloc()
方法,都需要稍后"%ms"
缓冲区以避免内存泄漏!
这有点过分了(特别是1024的限制),但应该让你开始走正确的道路。
示例:
free()
还有其他方法。例如,#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/* tested with user_data.txt containing "12 Barney 42" or "12 Barney" */
struct myret {
int age;
char *name;
char *affiliation_number;
};
int obtain_name_affiliation_number(struct myret *r)
{
int success = 0;
int age;
char *name = 0;
char *affiliation_number = 0;
FILE *user_data = fopen("user_data.txt", "r");
if(user_data)
{
#if 0 /* use if you have "%ms" */
if((1 == fscanf(user_data, "%d", &age)) &&
(1 == fscanf(user_data, "%ms", &name)) &&
(1 == fscanf(user_data, "%ms", &affiliation_number)))
{
success = 1;
} else {
/* a small annoyance: if only the first "%ms" succeeded,
* we need to free it:
*/
if(name)
free(name);
}
#else
char buffer[1024];
/* This if-structure can be used with the "%ms" as well, and
* would make the "annoyance" look a lot cleaner
*/
if(1 == fscanf(user_data, "%d", &age))
{
if(1 == fscanf(user_data, "%1023s", buffer))
{
name = strdup(buffer);
if(1 == fscanf(user_data, "%1023s", buffer))
{
affiliation_number = strdup(buffer);
success = 1;
}
}
}
#endif
fclose(user_data);
} else perror("error opening data file");
if(success)
{
r->age = age;
r->name = name;
r->affiliation_number = affiliation_number;
}
return success;
}
int main(void)
{
struct myret r;
int rc = obtain_name_affiliation_number(&r);
if(rc) {
printf("%d %s %s\n", r.age, r.name, r.affiliation_number);
free(r.name);
free(r.affiliation_number);
}
else
fputs("an error occurred reading data\n", stderr);
getchar();
return 0;
}
和name
可以在结构中声明为affiliation_number
,但这个数字几乎不可能提前选择,并且有任何正确性的希望。相反,这很常见:
char name[512];
然后其他两个函数变为(假设#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct myret *myret_alloc(int age, char *name, char *affiliation_number)
{
struct myret *r = 0;
if(r = (struct myret*)calloc(1, sizeof(struct myret))) {
r->age = age;
r->name = name; /* or use r->name = strdup(name); */
r->affiliation_number = affiliation_number;
/* note that using strdup would mean the calling function should
* do its own cleanup of its own name and affiliation_number vars
*/
}
return r;
}
void myret_free(struct myret *r)
{
/* this can be called on partially-allocated myret objects */
if(r->affiliation_number)
free(r->affiliation_number);
if(r->name)
free(r->name);
free(r);
}
可以fscanf
):
"%ms"
您也可以同时对所有三个人使用struct myret *obtain_name_affiliation_number(void)
{
struct myret *r = (struct myret*)0;
FILE *user_data = fopen("user_data.txt", "r");
if(user_data)
{
int age;
char *name = 0; /* the 0 allows us to see if it was used later */
char *affiliation_number = 0;
if((1 == fscanf(user_data, "%d", &age)) &&
(1 == fscanf(user_data, "%ms", &name)) &&
(1 == fscanf(user_data, "%ms", &affiliation_number)))
{
/* The name and affiliation_number were malloc()ed by "%ms"
* so there's nothing to clean up in this function, and
* we can let myret_free() just free those memory areas.
* This also means myret_alloc doesn't need strdup().
*/
r = myret_alloc(age, name, affiliation_number);
} else {
if(name) /* clean up name if it got allocated */
free(name);
}
fclose(user_data);
} else perror("error opening data file");
return r;
}
int main(void)
{
struct myret *r = obtain_name_affiliation_number();
if(r) {
printf("%d %s %s\n", r->age, r->name, r->affiliation_number);
myret_free(r);
}
else
fputs("an error occurred reading data\n", stderr);
getchar();
return 0;
}
:
fscanf
祝你好运!
答案 3 :(得分:0)
首先,您需要malloc
内存来存储您的数据,否则将无法存储它:
char *affiliation_number = (char*) malloc(STRING_LENGTH * sizeof (char));
如果malloc
失败,它将返回NULL
,您必须检查此错误情况:
if (!affiliation_number) {
// report error
}
然后,affiliation_number
已经是指针,您不需要&
:
fscanf(user_data, "%s", affiliation_number);
name
相同。
答案 4 :(得分:0)
首先,当您使用malloc();
free();
和char* a="always use malloc";
编译器将其用作const char * a
char* a;
分配内存free();
以避免内存泄漏