C++ 指针必须在使用前初始化,那么如何理解char*p?

C++ 指针必须在使用前初始化,那么如何理解char*p?,c++,c,pointers,C++,C,Pointers,新学员;关于指针的一些困惑 正如我从书本上学到的,在使用指针之前,它必须被初始化,所以我们通常这样使用 int a = 12; int * p = &a; 所以我理解为什么int*p=12是错误的,因为它没有地址 然后我今天在编码时发现了一些东西,即: char * months[12] = {"Jan", "Feb", "Mar", "April", "May" , "Jun", "Jul" ,"Aug","Sep","Oct","Nov","Dec"}; 然后我想到了

新学员;关于指针的一些困惑

正如我从书本上学到的,在使用指针之前,它必须被初始化,所以我们通常这样使用

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 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};
但是,以下不是使用初始值设定项列表中的整型文字初始化变量的有效方法:

int iarr[] = {1, 2, 3};
int iarr[10] = {1, 2, 3};
int const* ip = {1, 2, 3};
这就是我所说的语言例外,允许使用字符串文本初始化
char const*

首先:

int a = 12;
int* p = &a;
这是因为
&a
是一个内存地址

int* p = 12;
这失败的主要原因是12不是内存地址。12本身没有地址也是事实,但是像
int*p=&12(正如您正确指出的那样,这不起作用)

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

int a[] = {1, 3, 7, 13};
它可以简单地转换为整数指针

int* p = a; // magic!
指针对象是
a
的第一个元素,因此
*p==1
。现在,您还可以执行
p[0]
(也就是1),
p[1]==3
p[3]==7
,以及
p[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的人认为这是一件有用的事情。

int*p=12
是错误的,因为赋值可能属于内存地址,也可能不属于内存地址。您正在强制
p
指向该位置。

char*p=“string”
是允许的,因为编译器已经为字符串设置了空格,并且
p
指向该字符串的第一个字符。

它归结为类型

<>在C和C++中,一个纯整数文字类型,如<代码> 12 <代码>是<代码> int >代码>。没有从类型
int
到类型
int*
的隐式转换,这很有意义:指针和整数在概念上是完全不同的。所以
int*p=12无效

在C语言中,像
“abc”
这样的纯字符串文字被转换成一个静态字符数组(大小正好足以存储
abc
加上一个终止的空字符)。类型“array of chars”可以隐式转换为类型
char*
(指向char的指针)-数组可以分解为指针。因此作业
char*p=“abc”是有效的


但有一个缺点:修改该数组(在C和C++中)是未定义的行为。在C++中,这种转换实际上是被禁止的(甚至非法的),而应该使用<代码> const char */COD>。

实际上,GCC编译器会警告您:

char* p = "hello";
这是因为“hello”现在被视为等同于const char*

所以这会更好:

const char* p = "hello";

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

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

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

在C++中,行为是相同的,但是C++对于同一事物使用不同的术语。在C++中,常量都被称为“文字”,但是它们都是rVals(除了字符串文字),所以不能取它们的地址。
C99添加了其他类型的数组文本。

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

int*  p;
int  *p;
int * p;
上面所有的声明都是一样的:一个指针p,它可以是NULL,也可以是内存中整数大小存储单元的地址

周四
int * p = &12;
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
"The quick brown fox jumped over the lazy dog"
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 */
int *p = &(int){12};