【问题标题】:Trouble with C++ PointersC++ 指针的问题
【发布时间】:2015-04-22 01:16:43
【问题描述】:

如果你看一下代码

#include <iostream>

enum Type
{
    INT,
    FLOAT,
    STRING,
};

void Print(void *pValue, Type eType)
{
    using namespace std;
    switch (eType)
    {
        case INT:
            cout << *static_cast<int*>(pValue) << endl;
            break;
        case FLOAT:
            cout << *static_cast<float*>(pValue) << endl;
            break;
        case STRING:
            cout << static_cast<char*>(pValue) << endl;
            break;
    }
}

int main()
{
    int nValue = 5;
    float fValue = 7.5;
    char *szValue = "Mollie";

    Print(&nValue, INT);
    Print(&fValue, FLOAT);
    Print(szValue, STRING);
    return 0;
}

char *szValue = "Mollie";这行让我很困惑。据我所知,指针是一个保存另一个变量地址的变量。我对那条线的问题显然是

  • 这段代码怎么把一个字符串接受成一个字符?我们没有指定这个 char 是一个数组。那怎么来的?
  • 我们为什么要为指针分配一个字符串?我以为我们只能为他们分配其他地址。那个指针从哪里得到它的地址?它在哪里存储价值?

我仍然是 C++ 新手,但我们将不胜感激。

更新:我从下面的答案中了解到,当我们说“它将每个字母分配给 szValue 附近的内存地址”时。字符串中的其余字符存储在 +1 地址中。 C++ 如何知道原始字符串中有多少个字符/地址?因为 szvalue 只包含第一个字符的地址。不是其他人吧?

来源:LearnCPP - Void Pointers

【问题讨论】:

  • 专业提示:避免使用void*。在 C++ 中,请改用 template
  • How come this code accepts a string into a char? We have not specified that this char is an array. Then how come? 因为 C++ 的规则说我们可以做到。
  • @Dai 我仍在学习如何编程 C++,因此在此过程中学习了 void 指针,但我会牢记这一建议。首选模板的任何具体原因?
  • @shadoweye14 void* 本质上是不安全的,而使用模板会保留所有类型信息。
  • @shadoweye14 我是认真的。当涉及到初始化和char * 时,“字符串”附加了特殊规则。我猜的主要原因是'C'(这是规则的来源)的原始设计者认为字符串是“特殊的”,因此需要一种易于使用的语法。 not 创建了这样一个特殊的语法,没有什么可以阻止的,但他们还是这样做了。

标签: c++ pointers


【解决方案1】:

简而言之,在 C++ 中,指针和数组几乎是一回事。对于编译器,定义*szValueszValue[] 时没有区别。

编译器将字符串文字存储在内存中,第一个符号地址实际上是字符串的值。当您将字符串分配给char * 时,您可能会对该内存块进行不同的使用(即,只需将此地址传递给某个函数或遍历符号)

请注意查看您找到的在线教程的更多页面pointers-arrays-and-pointer-arithmetic。但是我认为学习 C++ 的最佳方法是阅读 Bjarne Stroustrup

编辑:(致谢)

指针和数组差不多,但不完全相同。以 char *x 和 char y[5] 为例。 'y' 就像一个指针,指向固定的东西,但 'x' 可能会被重新分配。 sizeof y 产生 5。当将 x 或 y 传递给函数时,'y' 的数组性消失了

【讨论】:

  • 当您说编译器时,两个定义之间没有区别。您能否更详细地解释一下编译器如何将*szvalue 处理为szvalue[]
  • 阅读nikkev的回答以获得进一步的解释
  • 指针不是数组,数组也不是指针。它们甚至不是同一种东西。
  • @CaptainObvlious 你能指出其中的区别吗?你不能用*szValue; szValue[4];吗?你不能用 void 指针做到这一点,这是真的
  • 指针和数组差不多,但不完全相同。以 char *x 和 char y[5] 为例。 'y' 就像一个指针,指向固定的东西,但 'x' 可能会被重新分配。 sizeof y 产生 5。当将 x 或 y 传递给函数时,'y' 的数组性消失了。
【解决方案2】:

我们为什么要为指针分配一个字符串?我以为我们只能为他们分配其他地址。那个指针从哪里得到它的地址?它在哪里存储值?

所以,有两件事。

除非它是sizeof 或一元&amp; 运算符(以及其他几个)的操作数,或者是用于在声明中初始化另一个数组的字符串文字,表达式 类型为“T 的 N 元素数组”将被转换(“decay”)为类型为“pointer toT”的表达式,表达式的值将是第一个地址数组的元素。

字符串字面量是“const char 的 N+1 元素数组”类型的表达式(C 中的普通 char),其中 N 是字符串中的字符数。

综合起来,

char *szValue = "Mollie";

字符串文字 "Mollie" 是“const char 的 7 元素数组”类型的表达式。由于它不是sizeof 或一元&amp; 运算符的操作数,并且由于它不用于初始化数组,因此它被转换为“const char 的指针”类型的表达式,并且它的value 是第一个元素的地址。

这很重要——数组不是指针。数组不会在任何地方存储指针值。在某些情况下,编译器会将指针表达式替换为数组,否则它们是两种完全不同的动物。

【讨论】:

  • 迄今为止我找到的最好的解释!谢谢。有几件事。当您说“字符串文字是“const char”的“N+1 个元素数组”类型的表达式时,N 是字符串的长度。数组的“+1”部分包含什么?是数组大小?或空终止符/
  • @shadoweye14:空终止符(我通常称它为 0 终止符以避免与 NULL 指针混淆)。
  • @shadoweye14:忘了提一下,如果你正在编写 C++,你应该使用 std::string 类而不是 C 风格的字符串。它让生活变得很多更简单。
  • 是的,这让我感到困惑。当您说const char 的指针时,它的值是第一个元素的地址。 1] 如果指针只保存第一个字符的地址,C++ 如何知道数组的长度。 2] 当我们调用指针 szvalue 时,它​​不应该只返回 M 作为数组的第一个元素而不是整个字符串吗?
  • @shadoweye14: 1) 它没有。 C 风格的字符串处理函数依赖于 0 终止符的存在来告诉它们字符串在哪里结束。 2)这取决于我们如何使用指针。是的,如果我们取消引用szValue,我们将得到'M' 的值;如果我们将该地址传递给带有%s 转换说明符的printf 之类的函数,该函数将“遍历”数组的长度,直到它看到0 终止符。
【解决方案3】:

前两个答案已经涵盖了问题的要点。指针和数组之间有很强的相似性(数组本身可以被认为是指向内存位置的指针)。例如,当数组名称用作函数的参数时,第一个元素的内存地址将传递给函数,而不是该位置的值(普通变量就是这种情况)。

上面的代码将字符串文字“Mollie”分配给 char 指针 szValue。因此,从“Mollie”中的“M”(被视为字符而不是字符串)开始,它将每个字母分配给 szValue 附近的内存地址。因此,指针变量 szValue 将指向字符串的第一个元素,相当于说 szValue[0](如果 szValue 被声明为 char 数组)。

希望这会有所帮助。

编辑: 更具体地说,szValue 指向字符串“Mollie”中第一个元素的内存地址,相当于使用 &szValue[0]。

【讨论】:

  • 太棒了!这为如何将指针用作数组提供了更多说明。谢谢
【解决方案4】:

char* s = "Mollie" 行在 C 和 C++ 中的含义是:

s 是一个指向字符的指针。 它被初始化指向包含字符Mo、...e 和一个空字符\0 的静态字符数组中的第一个字符。

指针是指向包含类型的一块内存的指针。 那块内存不一定是变量。

【讨论】:

    【解决方案5】:

    这段代码怎么会接受一个字符串变成一个字符?

    您的代码实际上并没有这样做,而是将第一个字符元素的地址分配给指针的值。 Viz,指针指向字符串的开头,指针加 1 现在将指向数组中的下一个字符,依此类推。

    我们没有指定这个 char 是一个数组。那怎么来的?

    你有char*,而不是char,这就是区别。另外,语义上char[]char* 是相同的。

    那个指针从哪里得到它的地址?

    编译器将文字字符串"Mollie" 粘贴在程序内存的只读部分中,该部分是在操作系统执行程序时加载的。 szValue 的值等于该字符串文字的地址。你会发现它是只读的,如果你试图修改它,你会得到一个段错误(在 *nix 上)或 Windows 上的访问冲突。

    【讨论】:

    • 我明白了。那么可以安全地假设指针被视为 const 指针吗?让它只读?作为我们提供的值,它本身就是一个常数。 "Mollie"
    【解决方案6】:

    char *foo 声明了一个 char 指针,这在 C 中就是数组的表示方式。

    所以:

    char *foo = "ABCD";
    

    foo[1] == 'B'

    这也意味着:

    *(foo + 1) == 'B'

    【讨论】:

      【解决方案7】:

      “Mollie”的实际类型是const char*。您可以将其视为chars 的数组。这就是为什么你可以写这样的东西:

      const char c = szValue[4];
      

      这里,szValue 只是一个指向字符串第一个字符的指针。因此,szValue + 1 将是指向第二个字符的指针,依此类推。

      【讨论】:

        【解决方案8】:

        你应该知道,当你使用char *szValue = "Mollie";时,它意味着你将常量字符串“Mollie”的地址分配给szValue,并且不能通过szValue改变值,因为“MOllie”是存储在常量区的常量值.

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-11-15
          • 2011-08-02
          • 2011-04-15
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多