【问题标题】:CS50.h segmentation fault if memory is not allocated to string如果内存未分配给字符串,则 CS50.h 分段错误
【发布时间】:2021-02-21 05:38:09
【问题描述】:

在处理 CS50 问题集(替换)时,我在运行代码时遇到了分段错误。经过一番搜索,我发现将内存(malloc)分配给字符串“输出”可以解决问题。但是我想了解为什么这里需要分配内存?

任何解释将不胜感激。

代码提取:-请注意我使用的是 cs50.h 库

string cipher(string input, string key) {

    string output=malloc(strlen(input)+1);

    for (int i=0, len = strlen(input); i<len; i++) {
        if(isalpha(input[i]) != 0) {

                output[i] = substitute(input[i], key);
            }

        else {
            output[i] = input[i];
        }
    }

    return output;
    free(output);
}

【问题讨论】:

  • 这里需要分配内存,原因与尚未分配的每个缓冲区都需要分配内存相同。顺便说一句,你想让你的return 语句在你的free 语句之后,而不是在它之前。
  • 请注意,C 中没有 string 类型。string 只是一种误导性的 cs50 编写 char * 的方式。
  • @goodvibration 感谢您的快速回复。为什么将 output 初始化为 output = "A....." 仍然给我一个分段错误?
  • 如果你用output = "A..." 替换对malloc 的调用,你的指针指向一个不能被修改的字符串字面量。当您通过output[i]= 为其赋值时,这是非法的。
  • return output; free(output); 这没有任何意义。 1: free 在你跳出它之前的函数时永远不会到达。 2:如果你要释放内存,那么调用者在你返回后就不能再使用它了。

标签: c segmentation-fault malloc cs50 c-strings


【解决方案1】:

尽我所能了解 CS50.h 字符串,我才知道

string output

只是声明了一个名为 output 的字符指针。因此,在您的代码中实际发生的是,除非您明确声明“strlen(input)+1”连续内存位置只属于输出,否则它们本质上是程序的空闲位置。因此,您的输出指针将仅包含第 0 个索引处的字符。该函数返回实际的“输出”,一个指针。同时,程序中的某些进程可能会使用除输出 [0] 之外的所有其他内存位置,因为它们从未属于输出字符串。输出只指向某个字符串的第一个字符。

C、C++ 中的边界检查基本上是由程序员完成的。任意 i 的 output[i] 永远不会出错,因为它是程序员的简单指针算法,即 output[i] = *(output+i)。 :)

【讨论】:

    【解决方案2】:

    首先是这个声明

    free(output);
    

    永远不会得到控制,因为它被放置在 return 语句之后

    return output;
    

    而且它没有任何意义。函数的调用者负责释放分配的内存。

    您需要动态分配内存,否则如果您将声明一个可变长度数组,例如

    char output[strlen(input)+1];
    

    然后在退出函数后,它将不再存在,并且尝试访问函数外部的数组会导致未定义的行为。

    如果你会写的话

    string output;
    

    相当于

    char *output;
    

    那么指针输出的值不确定,因为它没有被初始化,也没有分配内存来复制源字符串。

    您可以在原地更改源字符串input,而无需再创建一个数组。

    这样写就够了

        if(isalpha(input[i]) != 0) {
    
                input[i] = substitute(input[i], key);
            }
    

    然后你可以放置语句

    return input;
    

    请注意,使用别名 string 来表示 char * 类型是个坏主意。

    函数声明如果改写成这样

    char * cipher(char *input, char *key);
    

    令人困惑。目前尚不清楚函数中是否正在更改字符串输入和键。

    如果你希望函数从源字符串返回一个新的字符串构建,那么函数声明应该看起来像

    char * cipher(const char *input, const char *key);
    

    这样回答你的问题

    但是我想了解为什么这里需要分配内存?

    如果你想从指针input指向的源字符串创建一个新字符串,那么很明显你需要分配一个新的字符数组来复制源字符串的元素。

    否则如果你想原地更改源字符串,则无需再创建一个数组。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-29
      • 2014-01-05
      • 2011-03-22
      相关资源
      最近更新 更多