【问题标题】:Make a StartsWith function in C getting "Segmentation fault", What's wrong?在 C 中创建一个 StartsWith 函数得到“分段错误”,怎么了?
【发布时间】:2018-02-10 02:34:19
【问题描述】:

我正在尝试创建一个 startswith 函数,如果我有一个字符串,则该函数由
"Hello I am kira"
将拆分为第一个单词
"Hello" Only

我真的尽了最大努力把它变成这个表格

#include <stdio.h>
unsigned char *startswith(unsigned char *str)
{
    char *result;
    char *cstr = (char *)str;     
    for (int i=0; cstr[i] != ' '; i++)
       result[i] = cstr[i];
    return(result);
}

int main()
{
    printf("%s\n",startswith("What is your name momo?"));
    return 0;
}

应该打印“在我的想象中”

What

newline 然后退出 0 但是我在编译时遇到了未知的神圣错误

Segmentation fault

我不明白为什么会发生这种情况,甚至无法找到问题所在
gcc 没有帮助或向我显示警告

stdio.h 标头只是为了不再打印结果
我知道有一种方法可以在不使用任何标准库的情况下实现这一目标,但我需要领先

谢谢!

【问题讨论】:

  • 您必须了解内存模型中堆栈的内容。 result 是函数的局部变量,作用域以函数本身结束。
  • 为此我将它设为指针 (*),顺便说一句,即使在范围内它也不起作用。
  • 所以现在你有一个指向一个不存在的位置,因为函数已经退出并且本地人被弹出。你认为这有意义吗?指针并不意味着专用分配,因此您需要堆内存,如下面的答案所述。
  • @KiraSama char *result; 声明了一个没有指向任何地方的未初始化字符指针。您需要分配内存并使result 指向该块,例如char *result = calloc (strlen (str) + 1, 1); 然后用if (result == NULL) { /* handle error */ } 验证分配,然后进入你的for循环。
  • 编译所有警告和调试信息(例如gcc -Wall -Wextra -gGCC...)然后学习如何使用调试器 gdbvalgrind

标签: c function implementation startswith


【解决方案1】:

result 中分配一些内存。 result=malloc(sizeof(char)*MAXLEN);

现在您正在访问存储在result 中的一些垃圾值。

访问一个未初始化的变量是Undefined Behavior


  • 你也可以分配strlen(str)+1,因为你知道不管结果如何,最多只要str

  • $7.20.3.1 另一点是您可以使用calloc 函数将空间初始化为所有位为零。这样做的好处是始终具有以空字符结尾的字符串,即使您不小心省略了 nul-termination1

1。 David C. Rankin 指出

【讨论】:

  • 谢谢!现在我可以看到我的代码做了什么并对其进行了改进
  • 您不妨为result 分配strlen (str) + 1 字符,因为它永远不需要比这更长。如果您使用calloc 而不是malloc,您会将所有内存初始化为0(确保您将始终有一个nul-terminated字符串,如果您意外省略nul-终止)
  • @DavidC.Rankin.:感谢您的加入。现在检查我的答案。
  • 喜欢,更完整并提供 OP 选项(以及一些额外的学习:)
【解决方案2】:

基本上你在这里做的是使用一个没有分配内存的指针。你需要使用 malloc 为结果变量分配内存,为此你需要包含 stdlib.h

#include <stdio.h>
#include<stdlib.h>
#define MAXLEN 1000
unsigned char *startswith(unsigned char *str)
{
    char *result = malloc(sizeof(char)*MAXLEN);
    char *cstr = (char *)str;     
    for (int i=0; cstr[i] != ' '; i++)
    result[i] = cstr[i];
    return(result);
}

int main()
{
    printf("%s\n",startswith("What is your name momo?"));
    return 0;
}

【讨论】:

  • 这是一个好的开始,但它会造成内存泄漏,因为从startswith() 返回的指针从未传递给free()。更好的解决方案是将startswith() 的返回值分配给char 指针变量,然后在printf() 函数使用该变量后将其传递给free()。更好的解决方案是将已经分配的内存块传递给startswith(),以便调用者可以按照strncpy() 的模式统一处理内存管理。
  • 哦,是的!我没有在这里使用它...使用 free() 是编写高效代码的好习惯。感谢您指出这一点!
【解决方案3】:

对这里发生的事情进行更深入的解释......您遇到了段错误,因为您正在取消引用指向您的进程不拥有的内存的指针。您的 char* result 指针未初始化,这意味着它可能包含任何类型的垃圾数据。当您尝试result[i] = cstr[i] 时,您正在调用undefined behavior(所以我不会再链接他们未定义的行为文档了),这仅仅意味着从此时开始执行程序会产生不可预知的结果。在您的情况下,UB 会出现段错误,尽管可能并非总是如此。

为了初始化您的指针,您必须使用malloc 或其类似函数之一为其分配一些空间。当你用完它时,你还应该free你的记忆。你的程序很短,在这种情况下它不是什么大问题(操作系统肯定会在进程退出时清理分配给进程的所有内存),但养成这个习惯是件好事。

#include <stdio.h>
#include <string.h>

// this function shouldn't modify str (and in fact modifying a string
// literal like you're passing in would be UB anyway), so make this
// a const char*
char *startswith(const char *str)
{
    // sizeof(char) is defined as 1 in the standard, so you can leave it out of the malloc expression
    char *result = malloc(strlen(str)+1);  // Assuming str has at least 1 space, this will guarantee enough space for result
    if (result == NULL)   // make sure malloc returned some memory for you
    {
        // handle the error here how you want
        fprintf(stderr, "out of memory!\n");
        exit(-1);
    }
    // no need for cstr
    int i;  // move i out of the loop so it will be in scope after the loop
    for (i=0; str[i] != ' '; i++)
       result[i] = str[i];
    // NUL terminate your string
    result[i] = '\0';

    // "return" isn't a function, parenthesis unnecessary.
    return result;
}

int main(void)
{
    // store the returned result to a variable so we can free it
    char* result = startswith("What is your name momo?");
    printf("%s\n", result);
    // clean up the memory
    free(result);
    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-19
    • 1970-01-01
    • 1970-01-01
    • 2015-01-12
    • 1970-01-01
    相关资源
    最近更新 更多