【问题标题】:char [1024] vs char *字符 [1024] 与字符 *
【发布时间】:2011-03-11 16:42:18
【问题描述】:

我正在尝试学习 C,但在使用 char* 和 char 数组时遇到了麻烦。我正在使用库中的通用哈希集容器(我不想详细描述)。该库包含函数

void *HashSetLookup(hashset *h, const void *elemAddr);

我必须用它在哈希集中搜索以查看元素是否已经存在(哈希和比较函数是哈希集结构的一部分)。在这种情况下,我使用哈希集来存储指向 C 字符串的指针,或者更具体地说 (char * *) 。我的问题是以下代码给出了分段错误:

    char word[1024];
    /* Some code that writes to the word buffer */
    HashSetLookup(stopList, &word);

虽然这段代码运行良好(并且符合预期):

    char word[1024];
    /* The same code as before that writes to the word buffer */
    char* tmp = strdup(word);
    HashSetLookup(stopList, &tmp);
    free(tmp);

我认为 char word[] 和 char* 基本上是一回事。唯一的区别是 char word[1024] 位于堆栈中,长度固定为 1024,但堆中的 tmp 仅占用必要的空间(strlen(word)+1)。

因此我不明白为什么我必须在堆中复制字符串才能调用此函数。为什么会这样? char* tmp = strdup("something") 和 char word[1024] = "something" 之间有什么更根本的区别吗?

【问题讨论】:

  • 显示第一个示例中写入 word 的代码。
  • 我没有看到变量 tmp 在第一个示例中的函数调用之前被声明/使用。
  • MAK,抱歉,这是一个错误。我现在已经修好了。
  • Jergason,我正在考虑这样做,但该代码基本上是五个函数调用的列表,它们都相当复杂。我认为这根本没有帮助。然而,我已经确定我实际上是在写字,所以这不是问题。事实上 word 将包含单词“BBC”(当然由 \0 关闭)。

标签: c char


【解决方案1】:

您一定在第一个示例中遗漏了一些内容,因为根本没有使用“单词”。

无论如何,在大多数环境中,当您编写 'char *s = "Hello World"' 时,它会在代码段上创建并且无法修改。代码段意味着它是可执行代码的一部分,不能修改,只能读取。当您尝试编写它时,您会遇到段错误。

但是,'char[]' 是在数据段上创建的,因此可以毫无问题地对其进行修改。

【讨论】:

  • 他在第一个示例的注释中说,有一些代码可以写入 word。
  • 你是对的。在第一个代码中,它应该是 HashSetLookup(stopList, &word),而不是 HashSetLookup(stopList, &tmp);我现在已经解决了。谢谢。
【解决方案2】:
【解决方案3】:

如果没有 HashSetLookup 的文档,这很难说。

但它需要一个 const void * 作为它的第二个参数,所以你应该传递 tmp,而不是 &tmp,因为 tmp 已经是一个指针。

我认为这里根本不需要 char **。

另外,您可能对 HashSetLookup() 返回的内容感兴趣。

【讨论】:

  • 感谢您的回答。我实际上需要存储 char** 因为 HashSet 会将 void 指针指向的任何内容复制到固定大小的内存块。这不适用于字符串,因为它们具有各种大小。因此,所有 HashSet 函数都需要接受 char**,因为我只想存储指向存储在堆中的字符串的指针。你说得对,我对 HashSetLookup() 返回的任何内容都感兴趣。但由于此时它崩溃了,我没有费心将它包含在代码中。
  • 您的签名和您传递的值并不代表这一点。如果您认为它现在可以正常工作,那很可能只是另一个错误。
【解决方案4】:

既然你提到了char**,我认为问题在于函数试图写入到第二个参数指向的位置,即当你写的时候:

HashSetLookup( stopList, &word );

它尝试为word 分配一个地址(这就是为什么它需要它的地址。),它用一个指针覆盖缓冲区。

下面这个愚蠢的 sn-p 证明了这一点(记住数组的地址仍然是它的第一个元素的地址):

#include <stdio.h>
#include <stdlib.h>

void func( void* boo )
{
        char** ptr = ( char** )boo;
        printf( "func: got %p\n", boo );
        *ptr = "bad func";
}

int main( int argc, char* argv[] )
{
        char buf[128], *p;
        func( &buf ); /* buf got overwritten */
        printf( "array: %s\n", buf );
        p = malloc( 128 );
        func( &p ); /* p got new value */
        printf( "malloc: %s\n", p );
        return 0;
}

【讨论】:

  • 一开始我也有类似的想法。但是,如果您查看 HashSetLookup 的原型,您会发现第二个参数是一个指向 const 的指针。其次,这只是一个查找函数,它根本不应该写任何东西。
【解决方案5】:

你提到你需要一个char **,问题就在这里:对于一个数组,word&amp;word 意味着同样的事情——数组内容的实际位置。使用指针时它起作用的原因是因为“指针”存储在不同的位置,而它指向到同一个数组。你不需要strdup,你只需要创建一个指针:

char* tmp = word;
HashSetLookup(stopList, &tmp);

【讨论】:

  • 很高兴它有效。这是数组和指针之间的细微差别之一。
  • -1 因为答案完全错误。如果您传递 tmp 或 &tmp,它确实会产生根本性的不同。自己尝试一下,你会发现还有别的东西出现。不过你可以使用 &tmp[0]。
  • 我想你误解了我的回答。 tmp&amp;tmp 显然不同,因为 tmp 是一个指针。但是word&amp;word 是相同的,因为word 是一个数组。我已经尝试了好几次,甚至在发布之前就这样做了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-27
  • 1970-01-01
  • 1970-01-01
  • 2020-03-30
  • 1970-01-01
  • 2012-12-31
  • 2013-12-04
相关资源
最近更新 更多