Ceryn
Ceryn

Reputation: 65

Pointers and assignment, how does it work with different types?

I'm doing "Learn C the hard way" for self-study coming from knowing a bit of Python. I have read several tutorials, but I can't get my head around how pointers and assignment works. I understand that if you dereference the pointer, you can directly give it a value as in:

int *anint = 42;

But what about specifically referencing the memory location of an already-created variable? Specifically, I tried:

char *pointer_to_strlit;
char *strlit = "some stuff";
pointer_to_strlit = &strlit;

Why does the following cause a segfault after I do this:

printf("I print strlit: %s\nI print it again by pointing to it: %s\nI print where the pointer is pointing: %p\n", strlit, *pointer_to_strlit, pointer_to_strlit);

The types in C seem really hard tell how they will behave and how to use pointers to reference the specific types. Is there a clear guide that specifically outlines the syntax for pointing to each different datatype (char, *char, *char[], int, struct, void, null, functions, etc.)? Even a list of steps that would help me understand the rule set would be useful.

Upvotes: 0

Views: 1059

Answers (3)

DPlusV
DPlusV

Reputation: 14326

Hang in there! Pointers will make sense after more practice. But when in doubt, try to reason about what each value means. Using pen and paper to try to draw each byte in memory really helps.

char *pointer_to_strlit; - here you declare a pointer to a character. As you probably already know, a string in C is represented by a pointer to the first character of that string. The string is expected to be null-terminated. This means that eventually there should be an ASCII 0 character indicating that the string has ended.

char *strlit = "some stuff"; - your program's memory will contain characters for this string (11 characters to be exact -- 10 for the text you see, and 1 for the null terminator). Here you declare another pointer, this time pointing to first character "s" from that string.

pointer_to_strlit = &strlit; - this sets the value of pointer_to_strlit to the address of the pointer strlit. This is probably not what you want here.

If things get confusing, try to think of each pointer as a plain old number -- that's essentially what a pointer is, a huge number representing an address in memory. Let's look at the above again:

char *pointer_to_strlit; - Here the value of pointer_to_strlit is undefined since you didn't set it yet.

char *strlit = "some stuff"; - Let's say the address of the first "s" is 1234500. The value of strlit will be that number, 1234500.

pointer_to_strlit = &strlit; - But what is the address of strlit itself? It's some other value, let's say 1234600. The value of pointer_to_strlit will now be 1234600.

Try to print pointer_to_strlit as a %s now, and your program will crash -- at the address 1234600 is not the first character of a string, but another number -- one of the bytes of the huge number, the pointer. The code will try to traverse what it thinks is a string to look for the null-terminator, eventually crashing when it reaches inaccessible memory.

Upvotes: 2

Ned Batchelder
Ned Batchelder

Reputation: 375484

int *anint = 42;

This declaration is incorrect. anint is a pointer to an int, but you've initialized it as an int.

char *pointer_to_strlit;
char *strlit = "some stuff";

These declarations are fine. "some stuff" is a string literal, which in C is a char *, so it's fine to initialize strlit with it.

pointer_to_strlit = &strlit;

This is incorrect. &strlit is a char**, since it's the address of a char*.

printf(
    "I print strlit: %s\n"
    "I print it again by pointing to it: %s\n"
    "I print where the pointer is pointing: %p\n", 
    strlit, *pointer_to_strlit, pointer_to_strlit
);

Here you use strlit as %s, which is fine. Then you use *pointer_to_strlit as %s, which is bad: %s expects a pointer to a null-terminated string, you gave it a char, so it segfaults.

Upvotes: 1

Mahesh
Mahesh

Reputation: 34615

int *anint = 42;

42 is an integer literal and anint is supposed to hold the address pointing to an integer and not by integer itself.

char *pointer_to_strlit;
char *strlit = "some stuff";    // Should be const char *strlit = "some stuff";
pointer_to_strlit = &strlit;    // Wrong

&strlit gives address of pointer ( i.e., char ** ) while pointer_to_strlit is of type char*. So, it should be

pointer_to_strlit = strlit;

String literals reside in read only location. Turn on the warnings and compiler should give you some decent messages.

Upvotes: 1

Related Questions