【问题标题】:Pointer, String Problem in CC中的指针,字符串问题
【发布时间】:2010-01-23 18:32:45
【问题描述】:

在第一次学习 C++ 之后,我第一次将 C 用于一个类项目,所以语法让我很痛苦……基本上,我需要将一个函数给出的字符串存储到一个单独的变量中以供以后使用。

我有一个这样声明的字符数组

char foo[];

我得到的一个函数将一堆字符分配到这个数组中(或指向字符的指针?)。我可以像这样打印出存储在 foo 中的实际字符串

printf("%s", foo);

我可以像这样将它的地址存储在不同的变量中

char *bar;

bar = &foo[0];

printf("%s", foo);

在这两种情况下都可以很好地输出完整的字符串。但是,如何将此字符串存储在不同的变量中?如果 foo 发生变化,那么 bar 将不再保存我需要的字符串,因为它只是指向 foo。我想到的任何东西都会给我编译器错误,例如

warning: initialization makes pointer from integer without a cast

希望这是足够的信息。提前感谢您的帮助。

【问题讨论】:

  • 感谢您的快速回答,我使用了 strdup 方法,效果很好。现在我可以回到作业的真正部分,不再担心语法。再次感谢。

标签: c string pointers char


【解决方案1】:

你需要复制字符串。

最简单的方法是使用堆分配:

char *bar = strdup(foo);

完成后不要忘记释放该分配:

free(bar);

如果您不想使用堆分配,您可以在堆栈上创建一个缓冲区并手动将其复制进去。您需要小心不要溢出缓冲区(并且您的缓冲区是 0 终止的,如果您的 src 比您的 dest 长,strncpy 不会为您执行此操作):

char copy[SOMESIZE];
strncpy(copy, foo, sizeof(copy) - 1);
copy[sizeof(copy) - 1] = '\0';    

如果你有可变长度数组支持,你可以使用它:

char copy[strlen(foo) + 1];
strcpy(copy, foo);

正如Christoph 在 cmets 中正确指出的那样,strdup 不是 C 标准的一部分。如果您使用的是 Windows,则需要使用 _strdup。如果你想绝对便携,你可以很容易地实现 strdup:

char *strdup(const char *orig)
{
    char *copy = (char *)malloc(strlen(orig) + 1);
    if (copy != NULL)
        strcpy(copy, orig);

    return copy;
}

【讨论】:

  • +1;请记住,strdup() 是 POSIX,而不是 ISO-C 标准库的一部分,因此如果您想要最大的可移植性,您可能必须自己重新实现它
  • @Christoph - 谢谢。长期以来,Posix 一直是我的主要开发平台,我忘记了其中的区别。无论如何,更新我的答案以提供更多信息。
  • strdup() 的 glibc 实现 (cvs.savannah.gnu.org/viewvc/%2Acheckout%2A/libc/string/…) 使用 memcpy() 而不是 strcpy(),我希望这会稍微快一些,因为您已经必须确定字符串的长度
【解决方案2】:

您需要使用strncpy 复制字符串或使用strdup 复制它:

char foo[] = "Hello World";
char* bar = strdup(foo);

foo[0] = 'B';
printf("%s", foo);
printf("%s", bar);

free(bar); // Don't forget to release the memory!

打印:

Bello World
Hello World

或者,如果您已经有一个要复制到的字符串:

char foo[] = "Hello World";
char bar[] = "Goodbye Cruel World";

strncpy(bar, foo, sizeof(bar)-1); 

foo[0] = 'B';
printf("%s", foo);
printf("%s", bar);

还有 rints:

Bello World
Hello World

strncpy 的第三个参数是要复制的最大字符数(以防止溢出)请注意,它比bar 缓冲区的长度小一,因此bar 可以以nul 结尾。另请注意,sizeof 仅在此处有效,因为bar 是本地数组。它不适用于char*,在这种情况下,您需要从外部知道大小,例如:

char foo[] = "Hello World";
size_t bar_len = 20;
char* bar = (char*)malloc(bar_len);

strncpy(bar, foo, bar_len-1); // CANNOT use sizeof(bar) here!

foo[0] = 'B';
printf("%s", foo);
printf("%s", bar);

free(bar); // Don't forget!

【讨论】:

  • strncpy 不是这样做的好方法。 strncpy always 复制 n 个字符,即使要复制的字符串更短,填充 0 个字符,浪费循环。此外,strncpy 不保证写入的字符串以 0 结尾,如果源字符串长于缓冲区的长度,它就会被截断,而没有终止 0。并且 -1 在这里没有帮助,因为 malloc 不保证内存归零.
【解决方案3】:

使用 strcpy 函数将字符串复制到另一个变量。

char *myStringVar;

strcpy(myStringVar, your_Function_Returning_String() )

如果返回的字符串超出范围,则为 myStringVar 分配内存。

编辑:

char *myStringVar = (char *)malloc(BUFFER_SIZE);

【讨论】:

  • strcpy() 需要一个足够大的缓冲区作为目标,而不是未初始化的指针
  • -1:由于分配内存失败,这将覆盖未初始化变量指向的任何随机位置
  • 仍然如果我只想使用 strcpy 来解决上述问题,应该对 strcpy 进行哪些更改才能正常工作?
  • 您需要确保 myStringVar 指向有效内存。您可以将其更改为堆栈分配char myStringVar[SIZE](尽管您需要小心缓冲区溢出),或者您可以在堆上分配它char *myStringVar = malloc(strlen(src) + 1)(并且您需要检查 malloc 不返回 NULL)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-09-23
相关资源
最近更新 更多