首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么多个fget语句覆盖字符数组?

为什么多个fget语句覆盖字符数组?
EN

Stack Overflow用户
提问于 2019-06-18 18:01:05
回答 2查看 530关注 0票数 0

下面的代码可以工作,但是如果我输入了10个以上的字符(比如10a‘s),输出将变成如下所示:

狗的名字?狗的品种?狗的名字:狗的品种:

为什么会这样呢?我怎么才能修好它呢?

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>

typedef struct Dog {
    char name[10];
    char breed[10];
} Dog;

Dog makeDog() {
    Dog dog;

    printf("Dog's name? ");
    fgets(dog.name, 10, stdin);

    printf("Dog's breed? ");
    fgets(dog.breed, 10, stdin);

    return dog;
}

int main() {
    printf("\n");

    Dog dog = makeDog();

    printf("\n");

    printf("Dog's name: %s", dog.name);
    printf("Dog's breed: %s \n", dog.breed);
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-06-18 19:30:09

下列拟议守则:

  1. 干净地编译
  2. 执行所需的功能
  3. 如果狗名太长,退出
  4. 移除狗名末尾的换行符。
  5. 移除犬种结束时的新线
  6. 不检查犬种长度的有效性
  7. 使用动态内存后正确清理
  8. 避免使用“魔术”数字
  9. 正确分配动态内存并检查/处理任何错误
  10. 使用:“最多8个字符”,以便为后置换行符和终止NUL字符留出空间

现在,拟议的守则:

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_NAME_LEN  10
#define MAX_BREED_LEN 10

typedef struct Dog 
{
    char name[ MAX_NAME_LEN ];
    char breed[ MAX_BREED_LEN ];
} Dog;

Dog * makeDog() 
{
    Dog *dog = malloc( sizeof( Dog ) );
    if( !dog )
    {
        perror( "malloc for struct Dog failed" );
        exit( EXIT_FAILURE );
    }

    printf("Dog's name? max 8 characters ");
    if( !fgets(dog->name, MAX_NAME_LEN, stdin) )
    {
        perror( "fgets for dog name failed" );
        exit( EXIT_FAILURE );
    }

    if( dog->name[ strlen( dog->name ) -1 ] != '\n' )
    {
        puts( "dog name too long, aborting" );
        exit( EXIT_FAILURE );
    }

    // remove trailing newline
    dog->name[ strcspn( dog->name, "\n" ) ] = '\0';

    printf("Dog's breed? max 8 characters");
    if( !fgets(dog->breed, MAX_BREED_LEN, stdin) )
    {
        perror( "fgets for dog breed failed" );
        exit( EXIT_FAILURE );
    }

    // remove trailing newline
    dog->breed[ strcspn( dog->name, "\n" ) ] = '\0';

    return dog;
}

int main() {
    printf("\n");

    Dog *dog = makeDog();

    printf("\n");

    printf("Dog's name: %s\n", dog->name);
    printf("Dog's breed: %s\n", dog->breed);

    free( dog );
}
票数 0
EN

Stack Overflow用户

发布于 2019-06-18 19:31:47

字符数组name10元素声明。

代码语言:javascript
复制
char name[10];

如果您正在使用下面的fgets调用

代码语言:javascript
复制
fgets(dog.name, 10, stdin);

在输入10字符'a'之后,fget调用将只从输入缓冲区读取9字符,并以终止的零字符'\0'追加数组。

因此,数组将包含字符串"aaaaaaaaa"。它与以下列方式初始化数组相同

代码语言:javascript
复制
char name[10[ = { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', '\0' };

之后,输入缓冲区将包含一个字符'a'和新行字符'\n'。这些字符将在下一次调用时读取。

代码语言:javascript
复制
fgets(dog.breed, 10, stdin);

因此,数组bread将包含字符串"a\n"

它与以下列方式初始化数组相同

代码语言:javascript
复制
char bread[10[ = { 'a', '\n', '\0' };

如果您想要存储在具有更多字符的数组字符串中,则应该放大数组。

例如,如果要为数组名称输入一个10字符字符串'a',则让tfo将该数组声明为具有12元素。为什么是12?因为除了10字符'a'和终止零字符之外,函数fgets还将尝试从输入缓冲区读取新的行字符'\n'。否则,该字符将被fgets的第二次调用读取。

若要从数组中删除新行字符,可以使用以下方法

代码语言:javascript
复制
#include <string.h>

//...

fgets( dog.name, 12, stdin );
dog.name[strcspn( dog.name, "\n" )] = '\0';
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56654689

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档