【问题标题】:Must the pointer be initialized before use , then how to understand char * p?使用前必须先初始化指针,那么char * p怎么理解呢?
【发布时间】:2014-05-24 07:47:41
【问题描述】:

新学习者;关于指针的一些难题;

我从书上了解到,在使用指针之前必须对其进行初始化,所以我们通常这样使用

int a = 12;

int * p = &a; 

所以我明白为什么int* p = 12 是错误的,因为它没有地址;

那我今天在编码的时候发现了一些东西,就是从这个:

char * months[12] = {"Jan", "Feb", "Mar", "April", "May" , "Jun", "Jul"    
,"Aug","Sep","Oct","Nov","Dec"};

然后我想到了另一个常用的情况,那就是:

char *p = "string"; (this is ok , why int * a = 12 can't be allowed ?)

我很困惑。它何时初始化以及如何初始化?为什么int * a = 12 不能自动初始化?也许是关于记忆的安排。

【问题讨论】:

  • char *p = "字符串";不行!编译器会让你这样做并发出警告,但这很危险,以后可能会导致问题。
  • @thang 不幸的是,它被允许但已弃用。 const char* p = "string"; 可以。
  • int *a=12 表示将a通常内存地址)设置为值 12(不将 a 指向的整数设置为 12)...但是字符串文字已经表示为 constant char 数组,可以转换为 constant char 指针...因此您可以将它们分配给指针,而不是复制的字符串,但复制对现有字符串的引用。
  • "我明白为什么 int* p = 12 是错误的,因为它没有地址;" - 不,这是错误的,因为12 不是地址
  • 这是错误的,因为 12 在许多系统上都不是有效地址。

标签: c++ c pointers


【解决方案1】:

首先:

int a = 12;
int* p = &a;

这是因为&a 是一个内存地址。

int* p = 12;

这主要是因为 12 不是内存地址。 12 本身没有地址也是事实,但这会更好地通过像int* p = &12; 这样的 sn-p 来反映(正如您正确指出的那样,这不起作用)。

指针的一个有趣特性是它们通常用于指定值列表的开始。例如,取这个整数数组:

int a[] = {1, 3, 7, 13};

它可以很容易地变成一个整数指针。

int* p = a; // magic!

指针是a 的第一个元素,所以*p == 1。现在,您还可以使用p[0](也是1)、p[1] == 3p[3] == 7p[4] == 13

char* foo = "bar" 起作用的原因是“bar”不是一个单一的值:它是一个伪装的字符数组。单个字符用单引号表示。事实上:

"bar"[0] == 'b'
"bar"[1] == 'a'
"bar"[2] == 'r'

编译器对字符串文字(带引号的字符串)有特殊的支持,可以将它们直接分配给指针。例如,char* foo = "bar" 是有效的。

符合 C99 的编译器还支持数组字面量。例如,int* p = (int [3]){1, 2, 3}; 是有效的。字符数组和int数组都会被赋予一个全局地址,因为做C的人觉得这样做很有用。

【讨论】:

  • 为了完整性:"bar"[3] == '\0'.
  • “与数组文字相反”:C 语言已经支持数组文字 15 年:stackoverflow.com/questions/5495983/…
  • 另外,可以在 C++ 中获取 int 文字的地址:template<typename T> int &as_value(T &&v) {return v;} ... &as_lvalue(12)
  • @zneak 我相信你错过了我评论的重点。请参阅ideone.com/08sVYR 并再次告诉我数组文字不能分配给指针。
  • sigh,将问题标记为 C 和 C++ 的混淆,好像它们是同一种语言...
【解决方案2】:

int* p = 12 是错误的,因为分配的值可能属于也可能不属于内存地址。您正在强制 p 指向该位置。
char *p = "string" 是允许的,因为编译器已经为字符串设置了空间,并且p 指向该字符串的第一个字符。

【讨论】:

    【解决方案3】:

    归结为类型。

    在 C 和 C++ 中,像 12 这样的纯整数文字的类型是 int。没有从 int 类型到 int* 类型的隐式转换,这是有道理的:指针和整数在概念上是完全不同的东西。所以int *p = 12;是无效的。

    在 C 中,像 "abc" 这样的纯字符串文字被转换为 static 字符数组(其大小正好足以存储 abc 加上一个终止的空字符)。 “字符数组”类型可隐式转换为char* 类型(指向字符的指针)——据说数组衰减为指针。所以赋值char *p = "abc";是有效的。

    但有一个问题:修改该数组(在 C 和 C++ 中)是未定义的行为。这种转换实际上在 C++ 中已被弃用(甚至是非法的),您应该改用 const char *

    【讨论】:

      【解决方案4】:

      实际上 gcc 编译器会警告你:

      char* p = "hello";
      

      这是因为“hello”现在被视为等同于 const char*。

      这样会更好:

      const char* p = "hello";
      

      但是正如其他人所描述的那样,“你好”有一个地址,该地址指向固定字符序列的开头。

      【讨论】:

        【解决方案5】:

        int* p = 12 是错误的,因为它所做的事情几乎绝对不是你认为的那样。假设您的编译器没有抱怨您试图将int 隐式转换为int *,这并不违法。您所做的是,将p 指向内存位置12,这几乎绝对是您不应该阅读的内容。赋值是合法的,但如果您取消引用该指针,您将处于未定义的行为领域。如果您处于用户模式,那么*(int*)12 可能是分段错误。

        【讨论】:

        • 如果编译器没有抱怨,那么它就不会符合要求。
        【解决方案6】:

        使用 C 术语,这两种情况之间的区别在于存在 字符串字面量,它们是一个 char 数组(因此是一个左值,因此您可以获取它们的地址或指向它们);但在 C90 中没有其他文字。 12 是一个整数常量,而不是文字。你不能这样做&(12),因为语言是这样说的。大括号括起来的初始值设定项列表不是值。常量是右值;文字是左值。

        在 C++ 中,行为是相同的,但是 C++ 对同一事物使用不同的术语。在 C++ 中,常量都称为“文字”,但它们也都是右值(字符串文字除外),因此您无法获取它们的地址。

        C99 添加了其他类型的数组字面量。

        【讨论】:

          【解决方案7】:

          该语言已经例外,并允许使用字符串文字来初始化char const*。一些编译器不那么严格,也允许使用字符串文字来初始化 char*

          更新,以回应 Pascal Cuoq 的评论

          在 C 和 C++ 中,以下是使用字符串字面量初始化变量的有效方法:

          char carr[] = "abc";
          char carr[10] = "abc";
          char const* cp = "abc";
          

          以下是在初始化列表中使用整数字面量初始化变量的有效方法:

          int iarr[] = {1, 2, 3};
          int iarr[10] = {1, 2, 3};
          

          但是,以下不是使用初始化列表中的整数文字初始化变量的有效方法:

          int const* ip = {1, 2, 3};
          

          这就是我所说的语言已经例外并允许使用字符串文字来初始化char const*时的意思。

          【讨论】:

          • 你在说什么语言?为什么使用字符串文字来初始化 char const * 是一个例外?字符串文字是一个表达式,当它用作初始化器时,它的行为就像任何其他表达式一样,在 C 或 C++ 中都没有“异常”。
          • @PascalCuoq,希望我对答案的更新解释了我的想法,更重要的是,如果您认为我错了,请给我一些参考资料来解释原因。
          • 您可以使用数组文字初始化甚至分配指针。您只需要使用正确的 C99 语法。请参阅其他答案。
          • @PascalCuoq,感谢您的指点。我不知道C99的那个功能。我的观点仍然适用于 C++。你不同意吗?
          • @RSahu {1,2,3} 不是整数文字。它是一个大括号括起来的初始化器。
          【解决方案8】:

          许多程序员对指定指针的语法感到困惑。

          int*  p;
          int  *p;
          int * p;
          

          以上所有内容都声明了相同的东西:一个指针 p,它要么是 NULL,要么是内存中整数大小的存储单元的地址。

          这样

          int * p = 12;
          

          声明一个指针 p,并将其赋值为 12。

          在 C 和 C++ 中,指针只是对编译器具有特殊意义的变量,因此您可以使用特殊语法来访问其值所在的内存位置。

          换一种方式想一想。

          想想数字“90210”。那可能是您的银行余额。可能是您出生后的小时数。

          这些都是对数字的简单“整数”解释。如果我告诉你它是一个邮政编码 - 突然它描述了一个地方。 90210 不是加利福尼亚州比佛利山庄,它是加利福尼亚州比佛利山庄的[邮政]地址

          同样,当你写作时

          int * p = 12;
          

          你说“12”是一个整数在内存中的地址,你会在指针变量p中记住这个事实。

          你可以写

          int * p = &12;
          

          这将强制编译器在包含 12 的本机整数表示的程序可执行文件中生成一个整数存储单元,然后它将生成将该整数的地址加载到变量 p 中的代码。

          char* p = "hello";
          

          非常不同。

          12;      // evaluates to an integer value of 12
          "hello"; // evaluates to an integer value which specifies the location of the characters { 'h', 'e', 'l', 'l', 'o', 0 } in memory, with a pointer cast.
          
          int i = 12; // legal
          char h = 'h'; // legal
          const char* p = "hello"; // legal
          uintptr_t p = "hello"; // legal
          

          C 和 C++ 中的双引号具有特殊含义,它们计算为指向其中包含的字符串的指针,而不是计算字符串本身。

          这是因为

          "The quick brown fox jumped over the lazy dog"
          

          不适合 CPU 寄存器(取决于您的机器,它是 32 位还是 64 位)。相反,文本被写入可执行文件,而程序则加载它的地址(放入寄存器)。这就是我们在 C/C++ 中所说的指针。

          【讨论】:

            【解决方案9】:

            我在 stackoverflow 上发现了一个很好的提示:总是用 NULL 初始化声明的指针。 这将有助于理解新创建的指针在没有进一步操作的情况下无法使用。

            因此应该遵循的操作必须为指针分配正确的地址(初始化该指针)。

            用原始代码做你可能打算做的事情

            int *p = 12;
            

            你必须做的例子:

            int *p;
            p = malloc(sizeof(p));  /* pointer p holds address of allocated memory */
            *p = 12;
            

            或另一个例子:

            int *p;
            const int a = 12;
            p = &a;            /* pointer p holds address of variable a */
            

            上面的其他人回答了为什么char *p = "string"; 是正确的。这只是指针初始化的另一种方式。

            同样,在 stackoverflow 上的answers 之一中,我为您的情况找到了非常好的选择:

            int *p = &(int){12};
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2015-01-09
              • 2016-11-26
              • 1970-01-01
              • 2011-04-10
              • 1970-01-01
              • 1970-01-01
              • 2021-08-17
              • 2012-08-23
              相关资源
              最近更新 更多