关于C中指针和数组等价的问题

Vis*_*ain 1 c

我试图测试我对指针的理解并编写了以下代码:

#include <stdio.h>
int main(){
    char array_of_chars[]="array of chars";
    char *pointer_to_a_char="pointer to a char";
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我对为什么 2 行代码是定义字符串的等效方法的理由是:

第一个创建一个大小不定的数组(受堆栈中可用内存的限制?),它存储类型为 char 的变量。

第二个创建了一个指向 char 类型变量的指针,然后通过 * 符号我们将其汇集到该内存地址在 RAM 中指向的位置,然后从该点开始写入我们的字符串。

以上编译没有错误。

然而,这个新代码给出了警告。

新代码:

#include <stdio.h>
int main(){
    int myint = 5;
    int *pointer_to_an_int = 5;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)
 warning: initialization makes pointer from integer without a cast [-Wint-conversion]
  int *pointer_to_an_int = 5;
Run Code Online (Sandbox Code Playgroud)

我只是想知道为什么我们会在第二种情况下收到警告,而在第一种情况下没有。

我有一种感觉,这与以下事实有关:在第一种情况下,我们定义了一个数组,它是一个内存地址,但在第二种情况下,我们正在定义一个不同的变量?我不知道警告的确切原因,希望有人能解释一下。

Ser*_*sta 6

哎呀,你还需要练习C语言……

第一个创建一个大小不定的数组(受堆栈中可用内存的限制?),它存储类型为 char 的变量。

不完全是:它创建一个数组,其大小将由初始化程序定义。因此,编译器将其视为:

char array_of_chars[15]="array of chars";  // 14 characters + the terminating null
Run Code Online (Sandbox Code Playgroud)

话虽如此,这是初始化字符数组的惯用方法......

第二个创建了一个指向 char 类型变量的指针,然后通过 * 符号我们将其汇集到该内存地址在 RAM 中指向的位置,然后从该点开始写入我们的字符串。

不完全是。"pointer to a char"是一个字符串文字,它只能像一个 const char 数组(*) 一样使用。所以这大致相当于:

const char arr[18] = "pointer to a char";      // we have a const char array "somewhere"
char *pointer_to_a_char = arr;                 // (2)
Run Code Online (Sandbox Code Playgroud)

所以你现在有一个指向 const 数组的非 const 指针......如果你以后使用类似pointer_to_char[2] = 'c';!

顺便说一句:在第 (2) 行中,arr是一个用作值的数组,因此它会衰减(它是 C 语言)指向其第一个元素的指针。这就是为什么你用一个指针值初始化你的指针,但有一个常量问题的原因。

现在回答你的问题:

int *pointer_to_an_int = 5;
Run Code Online (Sandbox Code Playgroud)

这将创建一个指向 int 的指针并用值 5初始化该指针。因此它几乎等同于:

int *pointer_to_an_int;
pointer_to_an_int = (int *) 5;
Run Code Online (Sandbox Code Playgroud)

当某些硬件寄存器映射到众所周知的地址时,这种初始化在低级代码中是有意义的,因此编译器接受它。但是这里 UB 是有保证的,如果您使用类似的东西,int j = *i;并且在许多实现中,您将通过访问进程不可用的内存来获得段错误。


(*) 从语言律师的角度来看,字符串文字只是一个char array(non const),因为它char *txt = "foo";是旧版本 C 语言中的常见习语。但是更改其中的任何元素都是明确的未定义行为,以允许编译器将它们存储在只读存储器中。长话短说,我们应该记住 is 应该按原样使用const