简体   繁体   English

关于C指针的说明

[英]clarification about C pointers

In the following example: 在以下示例中:

int *i;
*i=1;

it produces a program to hang, because I know that I am putting a value directly to a memory position. 它会产生一个挂起的程序,因为我知道我将一个值直接放入内存位置。

The question that I have is why the following: 我的问题是为什么要执行以下操作:

int *i=1;

only produces a warning related to a casting of an integer and does not hang the program? 只产生与整数转换有关的警告,而不会挂起程序?

and why this instruction does not produce not an error nor a warning? 为什么该指令不产生错误也没有警告?

char *s="acd";

if I am using something similar to the example before 如果我正在使用类似于之前的示例

Thanks 谢谢

Let's talk about the 3 cases individually: 让我们分别讨论这三种情况:

int *i;
*i=1;

The first line allocates memory for a pointer, but does not initialize it, leaving i with a random garbage value. 第一行为指针分配内存,但不初始化它,使i保留随机垃圾值。 The second line tries to write to the memory address spelled out by the random garbage, causing undefined behaviour at runtime. 第二行尝试写入由随机垃圾说明的内存地址,从而在运行时导致未定义的行为。

int *i=1;

This allocates memory for a pointer and assigns it the value 1 (ie the memory address 0x1 ). 这为指针分配内存并为其分配值1(即内存地址0x1 )。 Since this implicitly casts the integer value 1 to a pointer, you get a warning, since it's extremely rare to ever initialize a pointer to a non-null memory address. 由于这会隐式地将整数值1强制转换为指针,因此您会收到警告,因为极少初始化指向非空内存地址的指针。

As an aside, if you were to do: 顺便说一句,如果您要执行以下操作:

int *i=1;
*i=1;

it would try to write the value 1 to the memory address 0x1 , causing the same undefined behaviour as in your first case. 它将尝试将值1写入内存地址0x1 ,从而导致与第一种情况相同的未定义行为。

char *s="acd";

This creates a null-terminated string on the stack and makes s point to it. 这会在堆栈上创建一个以null终止的字符串,并指向它。 String literals are the natural thing to assign to a char *, so no warning. 字符串文字是分配给char *的自然事物,因此没有警告。

Your first case is the only one where you are trying to write to memory: 您的第一种情况是您尝试写入内存的唯一情况:

int *i; // i is a pointer but it's value is undefined
*i = 1; // Whoops, you just wrote to a random memory location.

int *i=1; // i is an invalid pointer (address 1), but you aren't writing to it

char *s="acd"; // s points to the string literal "acd" - again: no write.
int *i = 1;

is equivalent to: 等效于:

int *i;
i = 1;

By the same token: 出于同样的原因:

char *s = "acd";

...is equivalent to: ...相当于:

char *s;
s = "acd";

The appearance of the asterisk in the type definition is notation for indicating that i and s are pointers. 类型定义中星号的出现是表示is是指针的表示法。 This is distinct from when you see the asterisk used outside of a type definition, where it indicates a dereference. 这与您看到类型定义之外使用星号(表示取消引用)不同。

So in these cases you are merely assigning the pointer value itself...not dereferencing it and writing to the memory it points to. 因此,在这些情况下,您只是在分配指针值本身,而不是对其进行解引用并写入其指向的内存。 The memory for the pointer itself is allocated on the stack and thus accounted for. 指针本身的内存在堆栈上分配,因此被占用。 Your danger comes when you dereference and try to write to it when it hasn't been initialized correctly. 当您取消引用并在未正确初始化时尝试对其进行写操作时,会出现危险。

Note that in the case of the string you can dereference into it. 请注意,在字符串的情况下,您可以取消引用它。 Four characters of memory for acd\\0 were set aside implicitly when the compiler saw the string literal...and then the literal evaluated to the address of that memory. 当编译器看到字符串文字时,隐式地预留了acd\\0四个内存字符,然后将文字求值到该内存的地址。 So your s pointer is good. 所以你s指针是好的。 Your i pointer is an arbitrary value which is very likely to not be readable on most systems. 您的i指针是一个任意值,在大多数系统上很可能无法读取。

int *i;

declares a pointer. 声明一个指针。 If done in a function this is an automatic variable and is not initialized . 如果在函数中完成,则这是一个自动变量,并且不会初始化 Then when you try to 然后,当您尝试

*i = 1;

you access some memory given by the value that was in the memory location assigned to the name i . 您访问由分配给名称i的内存位置中的值所给定的某些内存。 You probably don't have permission to access that memory, so your program crashes. 您可能没有访问该内存的权限,因此程序崩溃。

When you write 当你写

int *i = 1;

you declare the pointer and initializes it to point at memory location 1. Notice that you haven't tried to write anything into memory location 1, just pointed i at it. 您声明了指针并将其初始化为指向内存位置1。请注意,您没有尝试将任何内容写入内存位置1,只需将i指向它即可。 If you did try to write to it you would get a segfault again. 如果您确实尝试对其进行写操作,则会再次出现段错误。

Your last case declares a character pointer to point at a string literal (because "string" evaluates to the address where that literal is stored) which is generally stored in a special part of memory that you have the right to read, but not to write. 您的最后一种情况声明了一个字符指针,该字符指针指向字符串文字(因为"string"值等于该文字存储的地址),该地址通常存储在您有权读取但不能写入的内存的特殊部分中。

For the first part, the declaration: 对于第一部分,声明:

int *i=1;

is actually the same as doing: 实际上与这样做相同:

int *i;
i=1;

Which is, the pointer i is declared to be at the memory location 1 (0x00000001 if you have a 32bit address space). 也就是说,指针i被声明为在内存位置1(如果您具有32位地址空间,则为0x00000001)。 The warning is merely because you're converting an integer into an address. 警告仅是因为您要将整数转换为地址。

For the second part, it's the correct syntax for declaring strings. 对于第二部分,这是声明字符串的正确语法。 Which is why it doesn't trigger errors. 这就是为什么它不会触发错误的原因。

In your first example 在第一个例子中

int *i;
*i = 1;

you declare a pointer and let it be uninitialized. 您声明一个指针并使其未初始化。 That is is uninitialized means that it basically have a random value, so the pointer points to a random memory location. 这是未初始化的,意味着它基本上具有随机值,因此指针指向随机存储器位置。 Then you try to set the memory at that location to a value, which may crash your program. 然后,您尝试将该位置的内存设置为一个值,这可能会使程序崩溃。 Using uninitialized pointers are undefined behaviour . 使用未初始化的指针是未定义的行为

In the second example, you actually initialize the pointer. 在第二个示例中,您实际上是初始化了指针。 You do not assign a value at the location where i points, but you actually make i point to memory address 1 . 您没有在i指向的位置分配值,而是实际上使i 指向内存地址1

The third example is just a variant of the second, where you tell the pointer s to point to the memory where the literal string "acd" is stored. 第三个示例只是第二个示例的变体,您在其中告诉指针s指向存储文字字符串"acd"的内存。

In the first example: 在第一个示例中:

int *i;
*i=1;

You are assigning 1 to the location pointed to by i, which is uninitialized so it most likely writing to a location that is not valid. 您正在将1分配给i所指向的位置,该位置尚未初始化,因此很有可能写入无效的位置。

In the second example: 在第二个示例中:

int *i = 1;

You are assigning the value 1 to the pointer value i - that is your are saying i is pointed to memory address 1. That is equivalent to: 您正在将值1分配给指针值i-就是说我指向内存地址1。这等效于:

int *i;
i = 1;

The warning occurs because i is of type int* and is of type int . 发生警告是因为i的类型为int*且类型为int

In the final example: 在最后一个示例中:

char *s="acd";

You are assigning s to point to a string literal. 您正在分配s以指向字符串文字。 The string literal is stored in static memory in the program so at run-time it is replaced with a valid address. 字符串文字存储在程序的静态内存中,因此在运行时会将其替换为有效地址。 The type of a stirng literal is char* , which is the same type as s so there is no warning. 搅动文字的类型是char* ,它与s相同,因此没有警告。

int *i;

declares the variable i to be a pointer to an int while 声明变量i为一个指向int的指针

*i = 1;

tries to store the integer 1 at whatever address is stored at i . 尝试将整数1存储在i处存储的任何地址。 As you execute this command before storing anything in i , this should be undefined behavior. 在将任何内容存储到i之前执行此命令时,这应该是未定义的行为。 It's likely that i contains some random value and that you're therefore trying to store 1 at a random address. 这可能是因为i包含了一些随机值,并且你因此尝试存储1在一个随机地址。

int *i = 1;

declares the variable i to be a pointer to an int and attempts to initialize that pointer to 1. Since 1 is an integer and not the address of an integer, you get a warning. 将变量i声明为一个指向int的指针,并尝试将该指针初始化为1。由于1是一个整数,而不是整数的地址,因此会出现警告。

A string literal like "acd" is, by definition, a NULL -terminated char array containing the characters in the string. 按照定义,像"acd"这样的字符串文字是一个以NULL结尾的char数组,其中包含字符串中的字符。 On assignment, this array decays into a pointer to a char , and as you're assigning it to a char * there are no problems. 赋值时,此数组衰减为一个指向char的指针,并且在将其分配给char *时没有问题。 I don't think you're supposed to modify the elements of that array, though, so it would be better to assign it to a const char * , something which gcc will likely be happy to warn you about. 不过,我认为您不应该修改该数组的元素,因此最好将其分配给const char * ,gcc可能会很乐意警告您。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM