【问题标题】:SIGSEV on strcmp of memset stringmemset 字符串的 strcmp 上的 SIGSEGV
【发布时间】:2019-06-28 16:20:29
【问题描述】:

在下面的程序中,我希望 for 循环在 3 个元素后停止。 但它会无限期地继续运行,后来由于核心转储而失败。

  1. malloc() needed forchar*[]`
  2. 如果我将 mem 设置为 0,strcmp 会失败吗?

.

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
        char* str[10]; memset(str,0,10);

        str[0]=malloc(sizeof(char)*(strlen("Sample")+1));
        str[1]=malloc(sizeof(char)*(strlen("Sample")+1));
        str[2]=malloc(sizeof(char)*(strlen("Sample")+1));

        strcpy(str[0],"Sample");
        strcpy(str[1],"Sample");
        strcpy(str[2],"Sample");



        int i=0;
        for(i=0;strcmp("",str[i])!=0;i++)
        {
                printf("%d\n",i);;
        }
        return 0;
}

编辑: 即使使用char* str[10]; memset(str,0,10*sizeof(char*));,代码仍然会提供核心转储

【问题讨论】:

  • 1.是的。 2.不。一些废话让我发表这个简短的评论。
  • 您只需将 10 个字节的数组归零,即 10 个指针。将 10 更改为 10 * sizeof(char *)。您不需要 malloc 中的 sizeof (char),因为根据定义,它是 1。是的,如果你想让strcmp() 工作,你需要 malloc 全部 10 个。 "" 和空指针是完全不同的东西。
  • 在做strcmp之前应该检查str[i]是否不是NULL
  • 即使您成功地将str[] 中未使用的条目清零,当您尝试在(可能)NULL 指针上调用strcmp 时仍然会遇到麻烦。所以,是的,你想要for(i=0; str[i] != NULL &amp;&amp; strcmp("",str[i])!=0; i++)(或者可能是缩写的str[i] &amp;&amp; strcmp("",str[i])!=0)。
  • 这是对您的问题“char*[] 需要malloc()”的回答。不,这个程序不需要malloc。你不需要它来分配你当前正在分配的三个“Sample”字符串,你也不需要它来分配str

标签: c strcmp memset


【解决方案1】:

总结 cmets 和其他答案中所述的所有内容,这里至少存在三个(或者,如果你想学究,四个)问题:

  1. 您需要memset(str, 0, 10*sizeof(char *)(但请参阅下面的#4)。
  2. 您需要在调用strcmp 之前检查空指针,在for 循环中使用str[i] != NULL &amp;&amp; strcmp("",str[i])!=0 之类的条件。
  3. 如果您曾经在数组中存储了 10 个非空字符串,则循环将结束,永远找不到空字符串。
  4. (pedantic) memset 不是初始化空指针数组的好方法。 (严格来说,它根本不能保证工作。)正如@user3121023 在评论中所建议的,更好的方法是char *str[10] = { NULL }

您可以考虑在单独的变量中保留显式计数,而不是使用空字符串(或空指针)作为字符串数组结尾的标记。这可能是更常见的方法。


附录。您在问是否需要分配字符串。确实需要为字符串分配内存,但您不一定需要通过调用malloc 来动态分配它。至少有三种方法可以实现必要的分配,其中两种方法由编译器为您完成。以下是所有三个的示例:

char sample1[] = "Sample 1";

char *sample2 = malloc(strlen("Sample 2") + 1);
strcpy(sample2, "Sample 2");

str[0] = "Sample 0";
str[1] = sample1;
str[2] = sample2;

【讨论】:

  • 是的,但我特意要求char *str; strcpy(str,"sample") 。这是非法的,但 eeroika 说它不是非法的,因为 malloc 没有完成,这是非法的,因为 str 未初始化。好吧,当我写char* str; 之后,除了malloc 之外我还需要初始化什么?
  • @anurag86 是的,如果你调用strcpy,你必须给它一个指向它可以写入的内存的指针。但即便如此,这仍然不意味着唯一的方法是通过malloc 获得它。例如,你可以很好地做到char sample4[20]; char *ptr = sample4; strcpy(ptr, "Sample 4");
【解决方案2】:
  1. char*[]` 需要 malloc()

在 C++ 中几乎不需要 malloc。

在 C 中,您通常确实需要 malloc,但前提是您需要动态分配。

一般来说,拥有 char*[] 并不意味着您一定需要动态分配,因此不需要 malloc。

如果我不对数组 str[] 的每个元素进行 malloc,那么在不为该字符串分配内存的情况下分配一个字符串会不会是错误的?

char* 不需要指向使用 malloc 分配的内存。例如,它可以直接指向字符串文字(仅在 C 中;在 C++ 中,您需要指向 const 的指针)。或者它可以指向栈上的内存。

不是 char *str;如果我不通过 malloc 为 str 分配内存,strcpy(str,"sample") 错误?

那是错误的,但不是因为你不使用 malloc。这是错误的,因为您将未初始化的指针传递给 strcpy。因此行为是未定义的。它与malloc无关。


  1. strcmp 会失败吗...

不清楚您所说的“失败”是什么意思。没有表示失败或错误的输出。对于某些输入,行为未定义。虽然未定义的行为是程序员的失败,但不能保证您可能认为是失败的行为。

...如果我设置为 0?

如果您传递一个指向 strcmp 的指针,该指针不是指向空终止字符串的指针,那么程序的行为是未定义的。

在您显示的程序中,您最终传递了未初始化的指针,或者一个被 memset 设置为 0 的指针,因此不能保证它们是指向空终止字符串的指针。因此程序的行为是不确定的。

我正在传递一个指向 0(null) 的指针,因此取消引用不应该面临没有以 null 结尾的字符串的问题,因为我们不会在 null 位置存储任何内容

就标准而言,不保证 Memset 为 0 为空。正如@ChristianGibbons 所指出的那样,即使在您的系统上可能为空,10 个字节也可能不足以容纳该系统上的 4 个指针,因此您实际上根本没有初始化所有指针。

即使您确实将指针初始化为空,空指针也不是指向空终止字符串的指针,因此将空指针传递给 strcmp 具有未定义的行为。

【讨论】:

  • @eeroika : 1. 我们在谈论 C。 2. 对于 char* str[],如果我不对数组 str[] 的每个元素进行 malloc,那么分配一个不会是错误的没有为这个字符串分配内存的字符串? 3. 在第 4 次迭代中,我传递了一个指向 0(null) 的指针,因此取消引用不应该面临没有以 null 结尾的字符串的问题,因为我们不会在 null 位置存储任何内容
  • @anurag86 假设您确实有一个空指针,这正是问题所在。取消引用空指针是非法的。
  • @anurag86 如果我们在谈论 C,那么您为什么将问题标记为 [c++]?
  • @eeroika :对于 char* str[],如果我不对数组 str[] 的每个元素进行 malloc,那么在不为该字符串分配内存的情况下分配一个字符串会不会是错误的?顺便说一句,我删除了 c++ 标签。
  • @eeroika: char *str="sample" 。这里sample 是字符串文字,str 不需要malloc,但是isn't char *str; strcpy(str,"sample") 错误如果我不通过malloc 为str 分配内存?因为在后一种情况下,str 仍然指向某个垃圾位置,并且在不通过 malloc 的情况下复制字符串是非法的。没有?
【解决方案3】:
for(i=0;strcmp("",str[i])!=0;i++)

你确实取消引用了未初始化的指针

for(i=0;str[i];i++)

但它不会像这样工作

memset(str,0,10);

不初始化整个数组

memset(str,0,10*sizeof(char *);

【讨论】:

  • 严格来说memset(str,0,10*sizeof(char *); 也没有正确初始化整个数组。
  • @SteveSummitate 如果我们忽略 50 年历史的 Unisys 机器的可移植性,它确实如此。我不知道任何不填充 NULL 的系统
  • 查看我的编辑。即使使用char* str[10]; memset(str,0,10*sizeof(char*));,它仍然会提供核心转储
  • @anurag86 那是因为你忽略了我们三个人现在提出的另一个建议。
猜你喜欢
  • 1970-01-01
  • 2010-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-24
  • 2011-09-06
  • 1970-01-01
  • 2015-05-10
相关资源
最近更新 更多