[英]Pointers to char* inside a struct in C
I have a probably stupid question... but I have defined a struct with some char* inside. 我有一个可能很愚蠢的问题...但是我定义了一个内部带有一些char *的结构。 Now when I try to change the values of that chars.
现在,当我尝试更改这些字符的值时。 It doesn't give problems when it's compiled, but when I execute it, the program stops.
编译时它不会出现问题,但是当我执行它时,程序会停止。
This is a test function that I made for checking where is the problem: 这是我用来检查问题出在哪里的测试功能:
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;
}
Thanks for everything =) 谢谢一切=)
You don't need to use &
to pass the address of a char *
, remove thoses &
: 您无需使用
&
传递char *
的地址,而删除那些&
:
fscanf(user_data, "%s", &name);
^
fscanf(user_data, "%s", &affiliation_number);
^
Also, allocate memory for name
and affiliation_number
before using them by malloc
for example: 另外,在通过
malloc
使用name
和affiliation_number
之前分配内存,例如:
char *name = malloc(100 * sizeof(char));
Just declaring a char *
does not allocate any memory for it. 仅声明一个
char *
不会为其分配任何内存。 You either need to specify a static size (eg char name[100]
) or need to allocate memory dynamically (eg by using malloc
). 您要么需要指定一个静态大小(例如
char name[100]
),要么需要动态分配内存(例如通过使用malloc
)。 Remember to free
the memory if you use malloc
when you are done. 如果完成后使用
malloc
,请记住要free
内存。
Another problem is the use of &
in fscanf
for char *
. 另一个问题是在
fscanf
为char *
使用&
。 The variable list in scanf
and fscanf
after format string is a list of pointers where to place the input values. 格式字符串后面的
scanf
和fscanf
的变量列表是放置输入值的指针的列表。 When we use type like int age
we need to pass &age
, as that &
before age
makes it a pointer to age
, ie a int *
. 当我们使用
int age
类的类型int age
我们需要传递&age
,因为在age
之前, &
使其成为指向age
的指针,即int *
。 But char *name
is already a pointer, so you don't need &
here. 但是
char *name
已经是一个指针,因此您不需要&
在这里。 By using &name
you are creating a pointer to pointer or char **
which you don't want here. 通过使用
&name
您将创建一个在此处不需要的指针或char **
指针。
You've allocated space for only the addresses of buffers for name and affiliation_number, but never allocated the buffers themselves for those addresses to point to. 您仅为name和affiliation_number的缓冲区地址分配了空间,但从未为这些地址指向缓冲区分配缓冲区。
Hence, when you use them in fscanf()
, problems occur. 因此,当您在
fscanf()
使用它们时,会出现问题。 The compiler warns you (gcc, anyway) with these notes that the pointers are the wrong type - they should be the address of the first byte in the target buffer you want fscanf
to overwrite: 编译器会通过以下注释警告您(无论如何为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]
Here are some things to do instead - if your system doesn't support fscanf's "%ms"
spec, try this: 相反,有些事情要做-如果您的系统不支持fscanf的
"%ms"
规范,请尝试以下操作:
char buffer[1024]
to read data into. char buffer[1024]
以将数据读入其中。 buffer
or &buffer[0]
(for certain purists) as the targets in the string fscanfs buffer
或&buffer[0]
(对于某些纯粹主义者)用作字符串fscanfs中的目标 %1023s
or the like to prevent the data read from overrunning the length of the buffer - overruns can drive your program insane. %1023s
之类的方法防止读取的数据超过缓冲区的长度-溢出会导致程序疯狂。 strdup
to clone the data into name
or affiliation_number
. strdup
将数据克隆为name
或affiliation_number
。 This will malloc()
a new memory piece sized to fit the string you read and copy the data into it. malloc()
一个新的内存块,其大小适合您读取的字符串并将数据复制到其中。 Whether you use those steps or the "%ms"
approach, the buffers need to be free()
ed later to avoid memory leaks! 无论您使用这些步骤还是使用
"%ms"
方法,缓冲区都需要稍后进行free()
编辑,以避免内存泄漏!
This is a bit simplistic (the limit of 1024 in particular), but should get you started down the right path. 这有点简单(特别是限制为1024),但是应该让您正确地开始。
Example: 例:
#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;
}
There are other approaches. 还有其他方法。 The
name
and affiliation_number
could be declared in the struct as char name[512];
name
和affiliation_number
可以在结构中声明为char name[512];
for example, but that number is almost impossible to choose in advance with any hope of correctness. 例如,但是几乎不可能事先选择这个数字,并且希望正确无误。 Instead, this is common:
相反,这很常见:
#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);
}
Then the other two functions become (assuming fscanf
can "%ms"
): 然后,其他两个函数变为(假设
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;
}
You could also use fscanf
for all three at once: 您也可以一次将
fscanf
用于所有这三个:
if(3 == fscanf(user_data, "%d %ms %ms", &age, &name, &affiliation_number))
...
Good luck! 祝好运!
First, you need to malloc
memory for your data, otherwise there will be nowhere to store it: 首先,你需要
malloc
内存为您的数据,否则将无处可存储它:
char *affiliation_number = (char*) malloc(STRING_LENGTH * sizeof (char));
If malloc
fails, it will return NULL
, you have to check for this error condition: 如果
malloc
失败,它将返回NULL
,您必须检查以下错误情况:
if (!affiliation_number) {
// report error
}
Then, affiliation_number
is already a pointer, you don't need &
in: 然后,
affiliation_number
已经是一个指针,您不需要&
在:
fscanf(user_data, "%s", affiliation_number);
Same for name
. name
相同。
First at all you must use malloc();
首先,您必须使用
malloc();
and free();
和
free();
when you're using char* a="always use malloc";
当您使用
char* a="always use malloc";
compiler uses it as const char* a
编译器将其用作const char * a
char* a;
char* a;
分配内存char* a;
when a will be used as a variable string free();
free();
after it to avoid memory leaks
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.