【问题标题】:C Char pointersC 字符指针
【发布时间】:2012-04-10 23:24:26
【问题描述】:

假设我们有一个指针数组:

char *ptr[30];

现在这工作正常,并且似乎没有做任何意想不到的事情! 我可以轻松输入姓名。

scanf("%s", ptr[1]);
scanf("%s", ptr[2]);
scanf("%s", ptr[3]);

printf("%s\n", ptr[1]);
printf("%s\n", ptr[2]);
printf("%s\n", ptr[3]);

我的问题是如果可以以这种方式使用指针来存储名称的结束数,那么为什么要使用 malloc。?在这种情况下,ptr[1] 不指向输入中的字符,而是指向新的输入本身。 例如,如果 ptr 有 mukul,ptr[1] 应该指向 'u' 如果像这样声明指针时没有分配空间,那么限制是什么?

【问题讨论】:

  • 另外,需要注意的是数组的第一个元素是ptr[0]。
  • 尝试在scanfs 和printfs 之间做一些事情。您应该会看到一些未定义的行为。
  • 是的 ptr[0] 肯定在那里!感谢您的回复!

标签: c pointers char


【解决方案1】:

指针不能那样使用。有时它可能会为您“工作”,但使用指针而不为其分配内存会导致 undefined behavior - 这意味着您的程序可能会出现异常行为并给您带来意想不到的结果。

请记住,仅仅因为您的程序编译并运行并不意味着它是正确的。在 C 语言中,有一整类被称为“未定义行为”的错误,其中许多错误编译器都会很乐意让您毫无怨言地去做。其中包括覆盖缓冲区、使用未初始化的变量或取消引用未指向合法分配的内存块的指针。表现出未定义行为的程序有时甚至看起来可以正常工作 - 但它们通常非常不稳定并且容易崩溃。

【讨论】:

  • 另外请告诉声明 char *ptr[30] ,表示有 30 个字符指针,即它可以指向 30 个不同的字符,因为它是一个指针数组,或者它可以指向 30 个不同的数组字符(在这种情况下是名称)?
  • 我的意思是它应该指向 30 个不同的字符,但在这里它被用来指向 30 个不同的名称,对吗?
  • @Mukul,在 C 中,char* 通常指向一个以 null 结尾的数组或字符序列(也称为“字符串”)。所以char *ptr[30] 是一个由 30 个字符指针组成的数组,或者你可以称它为一个由 30 个“字符串”组成的数组。请注意,char* 不必指向以 null 结尾的字符数组 - 它也可以指向单个 char。但在常见用法中,char* 指向一个以 null 结尾的字符串。
【解决方案2】:

如果您使用示例中的内容,您只需改写 ptr 数组之后的其他位置。大多数编译器实际上应该至少给出一个警告。你的程序在大多数系统上都会崩溃,你很幸运。

【讨论】:

    【解决方案3】:

    当你定义一个像这样的指针时:

    char *ptr = 0; // NULL pointer: dereferencing it will crash
    puts(ptr);    // crash
    

    您只需创建一个指向内存中某个位置的链接:

    ptr = "string"; // dereferencing it will show the string
    puts(ptr);     // displaying "string"
    

    因此,拥有一个指针数组只会创建一个对其他变量的引用列表。

    要引用内存中的某个位置,然后必须为指针分配变量,或者为每个指针分配内存。

    【讨论】:

    • 所以指针说 char *c;可以指向一个字符,也可以指向一个字符数组..?什么更正确。?如果它只指向一个字符然后执行 c++ 并再次存储一些东西,它应该覆盖!
    • 指针可以指向任意大小的数据,不一定与指针的类型相同。目标是否为数组取决于您。变量是内存位置。指针是对内存的引用。
    • 这是正确的,但是做指针++应该总是指向下一个内存位置。如果一个数组已经存储在以前的位置,这个位置应该被占用吗?
    • 当指针递增时,它会递增其类型的字节数(对于 long 结构可能是很多字节),当然,您应该只遍历这种方式为防止发生崩溃而预先分配的内存。
    【解决方案4】:

    您已经为 30 个指针分配了空间,但您还没有将它们初始化为指向任何有意义的地方。除非您在函数之外声明数组,否则数组中的每个元素都将包含一些随机位串,这些位串可能对应于可写内存位置,也可能不对应。如果我们画一张图,它看起来像这样(所有地址都是凭空提取的;不要假设这对应于任何真实架构):

    项目地址 0x00 0x01 0x02 0x03 ---- -------- ---- ---- ---- ---- 指针 0xbbc81230 0x?? 0x?? 0x?? 0x?? 0xbbc81234 0x?? 0x?? 0x?? 0x?? 0xbbc81238 0x?? 0x?? 0x?? 0x?? ... 0xbbc812a8 0x?? 0x?? 0x?? 0x??

    其中0x?? 表示随机字节值。对于您描述的行为,每个随机值恰好指向可写内存,并且写入存储在那里的任何内容恰好不会立即产生任何不良影响.

    Bad juju:它看起来您的代码运行正常,但实际上它的行为非常糟糕,并且可能导致程序中其他地方出现一些令人讨厌的运行时问题,这对调试来说很痛苦。

    在尝试写入之前,您需要将ptr 数组的每个元素显式设置为指向有效的内存位置。

    假设我们添加以下代码:

    ptr[0] = malloc(strlen("foo") + 1);
    strcpy(ptr[0], "foo");
    ptr[1] = malloc(strlen("bar") + 1);
    strcpy(ptr[1], "bar");
    

    我们动态分配了一些额外的内存来保存几个字符串,并将指向这些新缓冲区的指针存储到ptr[0] 和ptr[1]。

    我们的图片现在看起来像这样:

    项目地址 0x00 0x01 0x02 0x03 ---- -------- ---- ---- ---- ---- 0x80ff0000 'f' 'o' 'o' 0x00 ... 0x80ffcdc0 'b' 'a' 'r' 0x00 ... 指针 0xbbc81230 0x80 0xff 0x00 0x00 0xbbc81234 0x80 0xff 0xcd 0xc0 0xbbc81238 0x?? 0x?? 0x?? 0x?? ... 0xbbc812a8 0x?? 0x?? 0x?? 0x??

    ptr[0] 现在包含一个缓冲区的地址,该缓冲区的大小可以容纳 4 个 char 值,我们将字符串“foo”复制到该缓冲区。同样,ptr[1] 包含另一个 4 字节缓冲区的地址,该缓冲区现在包含字符串“bar”。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-06-28
      • 2011-05-12
      • 2012-03-22
      • 2016-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多