使用getchar()读取两个字符串,然后在C中打印这些字符串时出现问题



这是我在C:中为两个函数编写的代码

// Begin
void readTrain(Train_t *train){

printf("Name des Zugs:");
char name[STR];
getlinee(name, STR);
strcpy(train->name, name);
printf("Name des Drivers:");
char namedriver[STR];
getlinee(namedriver, STR);
strcpy(train->driver, namedriver);
}
void getlinee(char *str, long num){
char c;
int i = 0;
while(((c=getchar())!='n') && (i<num)){
*str = c;
str++;
i++;
}
printf("i is %dn", i);
*str = '';
fflush(stdin);
}
// End

因此,使用void getlinee(char*str,long-num(函数,我希望获得第一个字符串char-name[str]和第二个字符串charnamedriver[str]的用户输入。最大字符串大小是STR(30个字符(,如果我在输入端有超过30个字符的第一个字符串("Name des Zuges"(,它将存储在名称[STR]中,然后我输入第二个字符串,它将被存储在名称驱动程序中,然后打印第一个字符串,我不会从用户输入中获得字符串(来自输入的前30个字符;附";对此,我只是不知道为什么。。。否则,如果第一个字符串满足30个字符的限制,则效果良好。在我的输出中,当第一个字符串的输入大于30个字符时,问题出现在第5行;Zugname";,为什么我只打印第一个字符串时也有第二个字符串…:

祖格人的名字:aaaaaaaaaa

我是30

驱动程序名称:xxxxxxxx

我是8

Zugname:aaaaaaaaaa aaaaaaa xxxxxxxx

驱动程序名称:xxxxxxxx

我认为您的问题是train->name没有正确地用''终止,因此当您调用printf("%s", train->name)时,函数会一直读取内存,直到找到''。在你的情况下,我想你的结构看起来像:

struct Train_t {
//...
char name[STR];
char driver[STR];
//...
};

getlinee()函数中,在最后一个字符之后写入''。特别是,如果输入长度超过30个字符,则复制前30个字符并在第31个字符(name[30](处添加''。这是第一个缓冲区溢出。

那么这个''到底写在哪里呢?好吧,在name[30],尽管你不应该在那里写作。然后,如果您在执行strcpy(train->name, name);时具有上述结构,那么您实际上会将一个31字节长的字符串:30个字符复制到train->名称,并且''将溢出到train->driver[0]中。这是第二次缓冲区溢出。

之后,您覆盖train->driver缓冲区,这样''就会消失,您在内存中的数据基本上看起来像:

train->name = "aaa...aaa" // no '' at the end so printf won't stop reading here
train->driver = "xxx"   // but there

您的数组大小有一个逐个错误——您有STR个字符的数组,您可以向其中读取多达STR个字符,但随后您存储了一个NUL终止符,总共需要(多达(STR + 1个字节。因此,每当您有一个最大大小的输入时,您就会运行数组的末尾,并得到未定义的行为。

STR - 1作为第二个参数传递给getlinee以获得最简单的修复。

关键问题

尺寸测试顺序错误,逐个关闭。((c=getchar())!='n') && (i<num)->CCD_ 22。否则就没有空间容纳空字符。在此处消耗多余字符的形式不正确。

getlinee()应在首次使用前声明。提示:启用所有编译器警告以节省时间。


其他

使用int c;而不是char c;来很好地区分典型的257个不同的可能结果与getchar()

fflush(stdin);未定义的行为。更好的代码会与其他代码一起在一行中消耗多余的字符。

CCD_ 28优于CCD_ 29。size_t是用于调整数组大小和索引的正确大小类型。

int i的类型应与num的类型相同。

更好的代码也可以测试EOF

while((i<num) && ((c=getchar())!='n') && (c != EOF)){

一个更好的设计是从getlinee()返回一些东西来指示成功,并识别问题,如文件结尾没有读取、输入错误、行太长以及参数问题,如str == NULLnum <= 0

我相信你有一个类似的结构:

typedef struct train_s
{
//...
char        name[STR];
char        driver[STR];
//...
}               Train_t;

当您尝试将''写入比STR(本例中为30(长的字符串时,实际上您将''写入name[STR],但您没有,因为name中最后一个长度为STR的元素的索引为STR-1(本例为29(,所以您正尝试在数组外写入''

而且,由于该结构中的两个字符串是相继存储的,因此您正在将''写入driver[0],并立即覆盖它,因此当打印出name时,printf直到到达driver的末尾才找到'',因此它打印这两个字符串。

解决这个问题应该很容易。

只需更改:

while(((c=getchar())!='n') && (i<num))

至:

while(((c=getchar())!='n') && (i<num - 1))

或者,正如我所做的,在数组大小上加1:

char name[STR + 1];
char driver[STR + 1];

最新更新