目标是将字符串字量的地址存储在char*中,该char*是struct的成员id。我想过使用数组。数组的问题是,如果我将最大字符数设置为7,用户可能输入小于7,这样会浪费内存。使用getchar()的好处是,我可以将max of char设置为7,但如果用户输入更少,也没关系。
typedef struct id
{
int age;
char* name;
}id;
id Mary;
char L;
int c =0;
printf("Enter your age: ");
scanf("%d",&Mary.age);
printf(" Enter your name: );
if( (L=getchar() != 'n' )
{
// stroring string litteral in char*
}
printf("%s", Mary.name);
这是一个常见的问题:"如何读取未知长度的输入字符串? "Daniel Kleinstein在他的回答中提到了几个通用的解决方案。我将在这里给出一个基于实现的答案
首先,你的程序不尝试存储字符串字面值,而是从输入流(例如stdin
)中读取的字符串。其次,不可能在char*
"中存储字符串"。字符串存储在由char*
指向的内存中。这个内存需要先分配。
下面的代码最接近您想要做的。它每次读取一个字符,并且每次将复制到的内存大小增加1字节。
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int age;
char *name;
} Id;
int main(void)
{
Id mary;
printf(" Enter your name: ");
size_t nameSize = 0U;
mary.name = NULL;
while (true)
{
mary.name = (char*) realloc(mary.name, ++nameSize); // cast is optional
if (mary.name == NULL)
{
printf("Memory allocation errorn");
exit(EXIT_FAILURE);
}
int ch = getchar(); // Note the `int` type, necessary to detect EOF
if (ch == 'n' || ch == EOF)
{
mary.name[nameSize - 1] = ' ';
break;
}
mary.name[nameSize - 1] = (char) ch;
}
printf("%sn", mary.name);
free(mary.name);
}
这不会浪费一个字节的内存,但是,频繁的内存重新分配会使该代码变慢。一个好的折衷方法是一次读取一个固定长度的字符串,而不是一次读取一个字符。要在实践中做到这一点:在堆栈上创建一个固定长度的缓冲区(例如64个字符),使用fgets
读入该缓冲区,并将该内容复制到mary.name
。如果字符串不适合缓冲区,则再次重复调用fgets
, reallocmary.name
并将缓冲区的内容附加到mary.name
,直到找到换行符。
另一个更简单的解决方案是为字符串设置最大长度,为该长度分配内存,读取最大长度的字符串,最后将内存重新分配到字符串的实际大小(可能更小)。
对于这类问题没有灵丹妙药。你的选择是:
-
使用具有最大长度的数组-但是正如您提到的,如果用户输入的长度较短,这可能是浪费的。然而,这通常是您在实际代码中找到的解决方案-在实践中,如果内存不是一个很大的问题,这比尝试处理涉及内存分配的其他动态解决方案更快更简单。
-
在用户输入名字之前询问他们的名字的长度,然后你可以使用
char* name = malloc(input_length);
或char name[input_length]
动态分配一个适当大小的缓冲区;C99中+。您还可以使用灵活的数组成员:struct name { size_t length; char buffer[]; }; struct name* username = malloc(sizeof(*username) + username_length);
-
如果你不想向用户询问用户名的长度,你可以在每个新的
getchar
之后做一个realloc
调用链,这将调整动态分配的数组的大小——但这是一个糟糕的想法,你甚至不应该考虑,除非你对程序中消耗的每个字节的内存感到压力。