简体   繁体   中英

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. 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 ). 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.

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.

char *s="acd";

This creates a null-terminated string on the stack and makes s point to it. String literals are the natural thing to assign to a char *, so no warning.

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. 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. So your s pointer is good. Your i pointer is an arbitrary value which is very likely to not be readable on most systems.

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 . 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. 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.

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). 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 .

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.

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.

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:

int *i;
i = 1;

The warning occurs because i is of type int* and is of type int .

In the final example:

char *s="acd";

You are assigning s to point to a string literal. 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.

int *i;

declares the variable i to be a pointer to an int while

*i = 1;

tries to store the integer 1 at whatever address is stored at i . As you execute this command before storing anything in i , this should be undefined behavior. It's likely that i contains some random value and that you're therefore trying to store 1 at a random address.

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.

A string literal like "acd" is, by definition, a NULL -terminated char array containing the characters in the string. On assignment, this array decays into a pointer to a char , and as you're assigning it to a char * there are no problems. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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