【问题标题】:Is that only an error with calling gets?这只是调用gets的错误吗?
【发布时间】:2014-12-27 23:06:56
【问题描述】:

我们接到了这个任务,想知道我们是否在解决方案中忽略了某些东西:

以下代码片段有问题。它会编译,但存在一个重要的语义问题,这将导致代码的行为与预期不同。确定问题和解决此问题的方法。

int main(void) 
{ 
    char * s = malloc(82 * sizeof(char)); 
    if(s==NULL) 
    {  
        perror("failed to allocate memory");  
        return EXIT_FAILURE; 
    } 
    fgets(s, sizeof(s), stdin); 
    if(s[strlen(s)-1] != '\n') 
    { 
        fprintf(stderr, "Error: you entered too much input"); 
        free(s); 
        return EXIT_FAILURE; 
    } 
    free(s); 
    return EXIT_SUCCESS; 
} 

我们认为错误在于fgets 函数,因为它会读取包括空终止字符在内的所有内容。所以我们相信有可能写一个尚未malloc'd 的角色。所以我们相信fget(s,sizeof(s)-1, stdin); 行将是解决办法。
我们是对的吗?还是有更多/其他错误?

【问题讨论】:

  • 您说“行为与预期不同”。你知道预期的行为是什么吗?
  • 读起来就像是我剪下来的家庭作业。
  • @duffmo 不是家庭作业问题,它是 RMIT 大学高级编程技术的过去考试问题。但它肯定是从过去的纸上剪切和粘贴的。如果你有兴趣,我可以把过去的试卷发给你。
  • @Woodrow 我不知道预期的行为是什么。我买了这个,讲师说这个问题在没有上下文的情况下是模棱两可的。虽然很有趣。

标签: c pointers semantics


【解决方案1】:

sizeof( s ) sizeof( char * ),这不是你想要的。

【讨论】:

  • 哦,好的。谢谢。我没有意识到 malloc'd 地址的大小只会返回已经 malloc'd 的类型的大小,而不是整个分配的内存。谢谢。
【解决方案2】:

sizeof(s) 很可能是 4 或 8。无论如何,它不会是 82。

【讨论】:

  • 哦,好的。谢谢。我没有意识到 malloc'd 地址的大小只会返回已经 malloc'd 的类型的大小,而不是整个分配的内存。谢谢。
  • @JoshuaTheeuf:您不分配地址,而是分配内存块。只需将概念指针和指针严格分开即可。
【解决方案3】:

这不是很长的代码,所以让我们全部获取:

  1. 没有包含。你需要:

    #include <stdio.h> // perror fgets fprintf
    #include <stdlib.h> // malloc free EXIT_FAILURE EXIT_SUCCESS
    #include <string.h> // strlen
    
  2. 避免使用魔法常数。如果你需要一些常量,在一个地方定义它(用一个有说服力的名字),然后总是引用它。

    #define MY_MAX_STRING_SIZE 82
    // Not length, that would be one less due to the terminator
    
  3. 风格点:char 永远是一个 char 大。

    char * s = malloc(MY_MAX_STRING_SIZE);
    
  4. 始终检查fgets 的返回值。如果失败,则为 NULL
  5. sizeof-operator 返回其操作数的大小,而不是它可能指向的缓冲区的大小。使用上面的常量:

    if(!fgets(s, MY_MAX_STRING_SIZE, stdin)) {
        perror("failed to read from stdin");
        free(s);
        return EXIT_FAILURE; 
    };
    
  6. 这三行相当于结束main

    return EXIT_SUCCESS;
    return 0;
    // C99+
    
  7. 为什么要使用动态分配?自动数组会更安全、更简单且性能更高:

    // includes...
    int main() {
        char s[82];
        if(!fgets(s, sizeof(s), stdin)) {
            perror("failed to read from stdin"); 
            return EXIT_FAILURE; 
        };
        if(s[strlen(s)-1] != '\n') 
        { 
            fprintf(stderr, "Error: you entered too much input"); 
            return EXIT_FAILURE; 
        } 
    }
    

【讨论】:

  • 您好,感谢您的回复。对于这个问题,我相信我们的讲师希望我们了解 sizeof 返回类型的大小,而不是分配的内存大小。
  • @JoshuaTheeuf:我敢肯定,当您也学会了所有其他内容时,您的讲师会很高兴。 ;-)
  • 我相信他会的。我只是更愿意与知情人士澄清我的理解。这就是为什么我发布了我认为是问题基础语义的解决方案。我错了哈哈。
  • 顺便说一句:有两个错误(fgetssizeof),一个省略号(包含),一个严重的编码标准违规(幻数),一个(可能由于人为的例子)动态分配应该是自动的和一些旁注。
猜你喜欢
  • 2012-08-25
  • 1970-01-01
  • 2020-09-12
  • 1970-01-01
  • 2017-06-04
  • 1970-01-01
  • 2012-03-18
  • 2015-03-10
  • 1970-01-01
相关资源
最近更新 更多