必须在使用前初始化指针,然后如何理解char * p?

时间:2014-05-24 07:47:42

标签: 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"};

然后又出现了另一个常用的情况,那就是:

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

我很困惑。什么时候初始化,如何?为什么int * a = 12无法自动初始化?也许是关于记忆安排的事情。

9 个答案:

答案 0 :(得分:8)

首先关闭:

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] == 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的人认为这是一件有用的事情。

答案 1 :(得分:3)

归结为类型。

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

在C中,像"abc"这样的普通字符串文字被翻译成一个 static 字符数组(大小足以存储abc加上一个终止空字符)。类型"字符数组"可以隐式转换为类型char*(指向char的指针) - 数组被称为衰变为指针。因此作业char *p = "abc";有效。

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

答案 2 :(得分:2)

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

答案 3 :(得分:2)

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

char* p = "hello";

这是因为"你好"现在被视为const char *的等价物。

所以这会更好:

const char* p = "hello";

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

答案 4 :(得分:0)

该语言已异常,并允许使用字符串文字来初始化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*时,这就是我的意思。

答案 5 :(得分:0)

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

答案 6 :(得分:0)

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

在C ++中,行为是相同的,但是C ++对同一件事使用不同的术语。在C ++中,常量都称为“文字”,但它们也都是rvalues(字符串文字除外),所以你不能拿它们的地址。

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

答案 7 :(得分:0)

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

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 ++的指针。

答案 8 :(得分:0)

我在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};