定义char和int时指针的区别是什么?

14

我了解指针的基本工作原理,但以下示例让我感到困惑。

int *myNum = 10; // Produces an error

char *myChar = "Something"; // Works fine

为什么赋值char可以工作但整数不行(可能是因为char被视为一个数组)?

还有就是当直接分配一个指针变量时,我感到困惑的是,它是否会自动获取地址?

char *myChar = "Something";

char myChar = "Something";
char *charAddr = &myChar;

这里会有什么区别,还是相等?


3
char myChar = "Something"; 不可行,因为 "Something" 不是一个字符。 - user253751
你要找的是数组指针转换 - hgiesel
@immibis 您可能意思是"Something"无法隐式转换为charchar myChar = 5.5;是合法的。 - M.M
我认为你只是混淆了单引号和双引号。int *myNum = 10;char *myChar = 'A'; 都是错误的。单引号用于字符,双引号用于常量字符数组,也称为C字符串字面值。话虽如此,char *myChar = "Something"; 只有一半是正确的,正如其他人指出的那样。严格的编译器将要求您声明const char *myChar,因为在现代架构中,您不能写入由myChar指向的数组元素。 - Peter - Reinstate Monica
5个回答

22
"Something"

基本上,它的缩写是:

static const char some_hidden_array[] = {'S', 'o', 'm', 'e', 't', 'h', 'i', 'n', 'g', '\0'};
some_hidden_array

也就是说,当你写下"Something"时,编译器会在后台生成一个数组,并给你一个指向该数组开头的指针。由于这已经是一个指向字符的指针,所以你不会有任何问题将它赋值给一个类型为"指向字符的指针"的变量(写作char*)。

10

is not并不表示任何相似的东西。它仅仅是数字10 - 它不是指向包含数字10的数组或类似的任何东西。

请注意,char是一个单独的字符,不是一个字符串,这就是为什么与大多数其他类型相比,字符串语法是不寻常的 - 一个字符串包含多个字符,而不仅仅是一个。如果你尝试使用一个普通的char,你会看到同样的结果:

char *myChar = 'a'; // error

或任何其他类型:

float *myFloat = 42.1f; // error

换句话说,如果 10 报错并不奇怪——相比之下,"Something" 没有报错才更奇怪。(至少在你了解字符串字面值的工作原理之前是这样的)。

10

这是同一件事情(编译器没有魔力)。默认情况下,像10这样的字面值是int值,而不是int*。

你需要进行强制类型转换:

int *myNum = (int*)10; // Need to cast
char *myChar = "Something"; // No need to cast "..." is already a char*
注意,这样引用指向绝对值的指针是危险的,因为您最终会在CPU内存中得到地址10。
关于您的第二个问题,“…”被视为内存中连续的char序列,类似于数组并等同于char*。
为了深入理解C、指针以及数组和指针之间的区别,您应该阅读Peter van der Linden的《Expert C Programming: Deep C Secrets》。

谢谢!至于第二个问题,我更像是问这两个是否相等?第一个例子是不是获取地址的简洁方式?谢谢! - J. Doe
1
如果这个回答解决了你的问题,请记得将其选择为你接受的答案。 - Kent Kostelac
4
"..." 不是 char*。我不建议使用 C 书籍来学习 C++,因为这两种语言的惯用法完全不同。 - Lightness Races in Orbit
@J.Doe 不,第二个例子根本不起作用。字符串字面值不是 char,而是 char[]。更改它,获取 char[] 的地址将为您提供指向指针的指针 - 在这种情况下,指向堆栈变量的指针,因此仅在范围退出之前定义。这非常重要,因为字符串字面值有点神奇 - 它们看起来“本地”,但实际上没有范围;原始指针在任何地方都有效,指向指针的指针则无效。 - Luaan

3
为什么赋值字符可以,但整数不行(可能是因为char被视为数组)?
你是对的,“Something”是一个字符串文字,可以被视为char数组。在“char *myChar = "Something";”之后,以下事情发生:分配了长度+1个字节的内存,其中将存储“Something”,myChar指向此内存的起始地址。字符串文字有些特殊。
这是一种使用常量值初始化数组的通用方法:
// valid initializations;
char s2[] = { 'a', 'b', 'c' };
int a[] = { 1, 2, 3 };
char s1[] = "123";

当直接分配指针变量时,什么让我困惑,它是否会自动获得地址?

是的。

请看c++文档中的8.5.2字符数组


2
当你执行char *myChar = "Something";时,你在内存中创建了一个只读字符串字面量,该字面量以空字符结尾。现在编译器有一些特殊之处,它将连续存储并以空字符结尾的“char”变量块解释为字符串。因此,基本上你创建了一个字符数组,当你执行*myChar*时,它返回字符串。
对于整数或任何其他数据类型,它区分int *ptr作为指向整数的指针,以及int ptr作为整数。你可能会遇到错误,因为你输入的地址可能无效/不可用。
此外,执行

char myChar = "Something";  //this is an error, since char can hold one character
char *charAddr = &myChar;

请注意,myChar&myChar是相同的,因为myChar是一个指针!

编辑:关于字符串字面值,请参考此处: 在C中修改char字符串是否可能?


谢谢您的解释,那么 type *var = something,总是在内存中创建一个只读变量吗?至于第二个问题,我更多的意思是如果这两个相等(更短的方式):) 谢谢! - J. Doe
@J.Doe 是的。看一下这个链接: https://dev59.com/yXNA5IYBdhLWcg3wUMDn - Sahil Arora
谢谢,这确实帮了很多忙。 - J. Doe
2
@J.Doe,不,type *var = something并不会创建一个只读变量。只有字符串字面值“Something”是只读的(而且它不是一个变量)。 - M.M

1

理论上来说,第一个int *myNum = 10是有意义的——特别是如果你知道地址十处有一个有用的int——但一般来说它很少有用,而且可能非常危险。

然而,有些指针赋值是被广泛使用并且相当安全的:

int *myNum = 0;

在现代CPU架构中的99.9%情况下,这与以下内容相同
int *myNum = NULL;

请查看<stddef.h>这里中NULL的定义。

一般来说,最好通过将指针变量设置为其他东西的地址来进行赋值。

int k, *p = &k;

1
谢谢!嗯,基本上,int *myNum = 10 // 指向地址“10”的指针,而不是实际包含值为10的变量的地址? - J. Doe
1
int *myNum = 0; 在所有系统中与 int *myNum = NULL; 相同,它创建了一个空指针。你可能会混淆空指针可能不是由全零位表示的事实(这对此代码没有影响)。 - M.M
@J.Doe 是的,你的困惑几乎正是为什么你需要添加显式转换以使其编译通过 - 这几乎总是一个错误,而不是预期的行为。在现代桌面/服务器系统上,您真的不希望使用指向手动选择地址的指针。虽然过去它很有用 - 例如,直接访问图形内存(或任何其他类型的设备)。随着硬件抽象,除了相当明显的 0/NULL 情况外,几乎没有合法的用途(根据 C 标准 始终 可行 :))。 - Luaan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接