【问题标题】:Is string an array or a pointer?字符串是数组还是指针?
【发布时间】:2016-09-29 22:11:53
【问题描述】:

我在这里得到了这个小程序,它带有预先分配的“计数”数字,然后将其解析为“xxx”的格式,其中 x 是 0 或相应的密码(例如,从 '6' 我得到 006 和从234 我得到 234)。当我得到它的时候

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

int main(int argc, char* argv[])
{
    int count = 0;

    char number[2] = {0};

    int base0 = count % 10;
    int base1 = ((count % 100) - base0) / 10;
    int base2 = ((count % 1000) - base1) / 100;
    sprintf(number, "%d%d%d", base2, base1, base0); //print into the number variable
    printf("%s\n", number); 
}

一切正常,但如果我用

切换“数字”变量定义
char* number = NULL;

我得到分段错误。这是为什么?它应该只是指向字符串的开头。

【问题讨论】:

  • 两者都是非法的并导致UB。你应该学习内存分配。
  • 在第一种情况下 (number[2] = {0}),您将 ASCII 字符零分配给数组“number”的每个元素。当您将 NULL 分配给 number 时,您只有一个指向名为“number”的字符的指针,该字符不指向内存地址。您必须为数字分配内存。
  • 我现在明白了。但是如何为此分配足够的内存呢? char *number = malloc(sizeof(999));有效,但 sizeof(999) 部分似乎不是最优雅的方式
  • sizeof(999)sizeof(int) 相同......这不是它的工作原理。
  • 那么我该如何优化它以仅为 0-999 分配内存?不是整个 int 范围?

标签: c arrays string printf


【解决方案1】:

在 C 中,字符串表示为字符数组;这条线

char number[2] = { 0 };

因此定义了一个用两个空字符初始化的两个字符数组('string')。

数组是一系列连续的(读作“彼此相邻”)内存块,每个内存块都可以通过下标运算符(方括号)单独访问。

当您将上面的行更改为

char* number = NULL;

您不再定义字符数组。在这种情况下,您现在定义了一个指向char 变量的指针。因为数组基本上是彼此相邻的内存块,如果您知道 first 元素在哪里,那么就可以找到其他任何元素。因此,由于引用运算符允许您访问指针所指向的值,因此您可以使用

访问字符串中的第 i 个元素
*(char + i)

在 C 中完全等价于

char[i]

现在,在您的情况下,您还没有将 char* 设置为指向包含真实字符串的实际内存,而是分配了 NULL 指针,这意味着“此指针不指向任何地方”。将 char* 视为字符串需要取消引用(跟随指针);但是,取消引用 NULL 指针是一种未定义的行为,在这种情况下会导致段错误

【讨论】:

    【解决方案2】:

    NULL 是一个定义明确的“无处”——它是一个保证不指向内存中的函数或对象的 invalid 指针值。当您将number 设置为NULL 时,您是在说number 没有指向任何有意义的地方。

    尝试处理无效指针会导致未定义的行为 - 在这种情况下,是段错误。

    数组和指针是一回事。在大多数情况下,数组 表达式 将“衰减”(被转换)为指针类型,但 object 始终是一个数组。

    【讨论】:

      【解决方案3】:

      “一切正常”,

      在那里等着。您已经严重短缺所需的内存。如果发生

        sprintf(number, "%d%d%d", base2, base1, base0); 
      

      number 需要更多内存才能保持在界限内,因此,您的程序通过访问超出界限的内存来调用undefined behavior。您需要分配 足够的 内存来保存由 number 保存的最终 sting

      无论如何,NULL 被定义为一个无效内存位置,访问它会再次调用 UB,所以你根本不能用它来存储任何东西。

      【讨论】:

      • 我不认为有短缺。最大数字是 999,我的 char number[2] = {0} 代码成功解析它。请参阅第 1 条下方的 cmets
      • 其实空指针根本不指向内存位置。而NULL 只是一个带有a(不是the空指针常量的宏。
      • @Olaf 对,所以 NULL 应该指向 一些 不应访问的无效内存位置。它只能用于比较和作为哨兵价值案例,对吧?
      • @SouravGhosh: 1) NULL 是一个宏,因此只是一些替换文本。根据定义,它不是“点”。 2) 根据定义,空指针 不指向任何地方。它不仅指向“无效”内存。 (实际上,常见实现使用的值有效地址,例如0x0 用于在地址0x0 处具有内存的ARM-MCU)。将其视为根本不是地址的特殊代码。比 C 更好的设计语言为此提供了一个特殊的关键字,例如NIL 在 Pascal/Modula/等中。或 C++11 nullptr 已明确添加以摆脱 0 的不良二元论。
      • 明确一点:我们应该强烈区分语言语义和实际实现语义。
      【解决方案4】:

      字符数[2];给你两个字节的数字内存 字符 * 数字 = 空;为 *number 提供零字节的内存。

      当您执行 sprintf 时,您将三个字节写入数字。 当说“char *number = null”时,你正在写入 null,这会导致段错误。

      当您执行 sprintf 时,您将 3 个字节写入 2 个字节的分配内存 - 您将 1 个额外字节覆盖到堆栈中。

      【讨论】:

        猜你喜欢
        • 2018-09-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-06
        • 2011-06-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多