【问题标题】:Why Can't we copy a string to Character Pointer WHEN we can assign a string directly to it?为什么我们不能将字符串复制到字符指针当我们可以直接分配一个字符串给它?
【发布时间】:2010-02-08 15:27:01
【问题描述】:

这段代码产生“p = hello world”:

#include "stdio.h"
#include "string.h"

int main(){
    char *p;
    p="hello world";
    printf("p is %s \n",p);
    return 0;
}

但是这段代码会产生分段错误:

#include "stdio.h"
#include "string.h"

int main() { 
    char *p;
    strcpy(p,"hello");
    printf("p is %s \n",p);
    return 0;
}

这段代码产生“p = hello”

#include "stdio.h"
#include "string.h"
#include "stdlib.h"
int main() {
  char *p;
  p=(char*)malloc (10);
  strcpy(p,"hello");
  printf("p is %s \n",p);
  return 0;

}

【问题讨论】:

    标签: c pointers


    【解决方案1】:

    p="hello world";(本次编辑时的第一种情况)的情况下,p 被初始化为指向包含字符串“hello world”的只读内存区域“ (字符串字面量)。这个只读内存区域是在编译时创建的。

    在导致分段错误的情况下(本次编辑时的第 2 种情况),p 未初始化,将任何内容复制到其中会产生不可预知的结果,因为p 指向的内存位置不是由代码指定。

    在将字符串复制到p 之前,您必须指定p 指向的内存。

    你可以在栈上分配这块内存

    char buf[BUFSIZ] = ""; /* local variable */

    在堆上

    char *buf = malloc(BUFSIZ); /* don't forget to free */

    或在 __DATA 段中。

    static char buf[BUFSIZ] = ""; /* global variable */

    然后您可以初始化p 以指向内存缓冲区。

    char *p = buf;

    这在概念上类似于初始化p 以指向只读内存中的字符串文字。与p 指向字符串文字的情况不同,您现在可以将字符串复制到字符指针,因为它不指向只读内存。

    注意:我特意创建了一个单独的缓冲区并初始化 p 以指向它以帮助说明我的观点。

    【讨论】:

    • 那么,为什么会这样呢? #include #include int main() { char *p; p="你好世界"; printf("p 是 %s \n",p);返回0; } 输出: p 是 hello world
    • 您在第一个中没有应对 p 的任何内容。您正在将该字符串文字的地址分配给 p。这就是它起作用的原因。
    • 通过将字符串文字的地址分配给 p,您指定了 p 指向的内存位置。
    • 注意:由于问题的变化,我更新了我的答案。
    【解决方案2】:

    原因是当你声明一个指针时,它实际上并没有指向任何有用的东西。 strcpy 需要一块内存才能将字符串复制到其中。它不会自动为您执行此操作。

    来自文档(重点是我的):

    复制 source 指向的 C 字符串 进入目的地指向的数组, 包括终止的 null 字符。

    为避免溢出, 目标指向的数组应为 足够长以包含相同的 C 字符串作为源(包括 终止空字符),和 不应该在内存中与 来源。

    你需要做到这一点,因为它是函数的先决条件。

    另外,在参数部分:

    目的地

    Pointer to the destination array where the content is to be copied.
    

    您需要确保destination 是指向数组的指针。

    【讨论】:

    • "当你声明一个指针时,它实际上并不指向任何东西——只是 NULL" 实际上它可以指向任何地方。未初始化不代表0。
    • @sepp2k:谢谢,我已经有一段时间没有编写任何 C/C++ 代码了。固定。
    【解决方案3】:

    没有免费的午餐 - 您需要获取和管理内存。如果您只是假设因为您可以访问指针内存应该在那里,那么您将遇到未指定的行为(可能是段错误)。

    【讨论】:

      【解决方案4】:

      因为在第一个示例中,指针p 包含一些随机垃圾,这些垃圾当时恰好在堆栈上,可能为零,也可能是其他任何东西,所以它指向...没人知道你的代码在哪里段,例如。操作系统做了正确的事情,并告诉您您正在违反规则并试图写入不属于您的内存。阅读the fine description of segmentation faults here

      如果您绝对想避免动态内存分配并且您知道源字符串的大小在编译时您可以像这样获取适当的堆栈空间:

      char buffer[6]; /* strlen( "hello" ) + 1 for zero terminator */
      strcpy( buffer, "hello" );
      

      但那是一条通往buffer overruns的危险路。

      【讨论】:

        【解决方案5】:

        请注意这两个工作示例的共同点:它们有一个p = 行,它为p 分配了一些东西。非工作示例不这样做。

        考虑这一行(来自第一个示例):

        p = "hello world";
        

        虽然它看起来像是“将字符串复制到 char 指针”,但事实并非如此。它将字符串的 位置 复制到指向字符的指针。这就是像 p 这样的指向字符的指针所存储的内容 - chars 的连续块的位置。

        同样,考虑第三个示例中的这一行:

        p = malloc(10);
        

        这也是复制一个位置 - 它将一个包含 10 个未初始化 chars 的块的位置复制到 p

        strcpy(dest, source) 将字符从source 指定的位置复制到dest 指定的位置。应该清楚的是,如果您从未将 p 设置为有效位置,则 strcpy(p, "hello") 无法做任何明智的事情 - 在您的第二个示例中,p 基本上是一个随机位置,然后您要求 strcpy()将某些内容复制到该位置。

        【讨论】:

          【解决方案6】:

          内存复制有两个不同的部分。第一个是您要复制的项目占用的内存(您在示例中使用 malloc() 函数创建),第二个是指向该内存块的指针(您称为 p)。这两个实体也必须为目标设置,然后才能进行复制。在您失败的第一个示例中,您没有为目标设置内存块(但在声明字符串 hello 时已为源隐式设置了内存块)。

          【讨论】:

            【解决方案7】:

            是的,这很烦人。您可以使用strdup 来缩短它:

            char *p = strdup("hello");
            printf("p is %s \n",p);
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2010-10-14
              • 2021-08-03
              • 1970-01-01
              • 1970-01-01
              • 2017-01-17
              • 1970-01-01
              • 1970-01-01
              • 2016-08-28
              相关资源
              最近更新 更多