How to Approach Pointers in C? [duplicate]

2020-07-09 10:22发布

I am very new to C and I have some problems learning about pointers. I experimented swapping and that's all what I can do with them :) I know that every variable has its own address in memory cells (this is what my lecturer told us) and every variable's value can be obtained by going to its associated address and then fetching the value stored in it. I've seen some function headers such as:

int doSomething(char **hihi);

my head is so confused. I know that pointer is a variable too and it only stores address information in its memory cell. I read that they are closely related to arrays

arr = &arr[0];

That's all what I know about pointers and I wonder how I can deepen my vision upon pointers. I searched the net and I could not find any useful cheatsheet covering pointers. And I also want to know why they are so important and is there any way to understand actually what is going on without using printf() to print their addresses(p) and values(\*p)??

标签: c pointers
13条回答
Root(大扎)
2楼-- · 2020-07-09 10:32

While reading K&R might be the best choice here I'll try to make it a bit clearer:

A pointer itself is a variable. But instead of storing a value it only stores an address. Think of it like an index: like in your address book the index for something you're searching for (say, the phone number to some name) it points to where the information is stored. In your address book it might say "look at page 23 to find the phone number of Joe". In case of the pointer it simply says "look at memory address 1234 to retrieve the information I'm pointing at." As the pointer value itself is only a memory address you can make arithmetics with it -- like adding values (which would be the same as accessing elements of an array: if the pointer is pointing to an array, the address following the one the pointer is pointing to will access the next element in the array). Your example function int doSomething(char *hihi) will have hihi pointing to the memory address you passed it when calling it. This is useful if you want to pass larger amounts of data -- instead of copying the data (which happens in a function like void blah(int a) with the value of a) you only copy its location.

I've left out some details in the above, but I hope it gives you at least some basic understanding. I strongly suggest reading K&R or a similar book on the topic.

查看更多
beautiful°
3楼-- · 2020-07-09 10:35

Printing addresses and values is a reasonable way to look at them. But if you can get a debugger up and running, that's much better, because you can follow pointers faster, watch them change as you step, and so on.

If you're familiar with "shortcuts" in Windows, or soft links in linux filesystems, then it might help, just as you're getting started, to think of a pointer as a shortcut (softlink) to another object (whether that object is a struct, a built-in type, another pointer, etc).

A shortcut is still a file. It takes up its own space on the disk drive, it refers to another file, and it can be modified to refer to a different file file from what it used to. Similarly, a pointer in C is an object which occupies memory, contains the address of another memory location, and can be changed to contain a different address just by assigning to it.

One difference is if you double-click a shortcut, it behaves as if you'd double-clicked the thing it points to. That's not the case with pointers - you always have to explicitly dereference a pointer with "*" or "->" in order to access the thing it points to. Another difference is that it's quite common to have pointers to pointers to something in C.

As for the jargon, you just have to learn it unfortunately. "int doSomething(char **hihi)" means "a function called doSomething, which returns an integer, and takes as a parameter a pointer to pointer a char". The crucial point is that "char ** hihi" means "a pointer-to-pointer-to-char. We will call the pointer-to-pointer-to-char hihi". You say that the "type" of hihi is char**, and that the "type" of *hihi (what you get when you dereference the pointer) is char*, and the type of **hihi is char.

Frequently in C, a pointer to a char means a string (in other words, it's a pointer to the first char in a NUL-terminated array). So often "char *" means "string", but it doesn't have to. It might just mean a pointer to one char. A bit like a shortcut to a 1-byte file in Windows (well, with FAT32 anyway), a pointer to a char in C is actually bigger than the thing it points to :-)

Likewise, a char** often means not just a pointer to one string-pointer, but to an array of string-pointers. It might not, but if it does then the following little picture might help:

hihi
 ____            ____                     ________     _________      _______
|____|   -----> |____|  *hihi       ---> |___A____|   |___B_____|    |___C___|
                |____|  *(hihi+1)   ------------------^              ^
                |____|  *(hihi+2)   ---------------------------------|
                | ...|    etc.

hihi points to the tower-block effort, which is my way of representing an array of pointers. As you already noted, I could have written hihi[0] in place of *hihi, hihi[1] in place of *(hihi+1), and so on.

This is a contiguous block of memory, and each pointer-sized chunk of it contains the address of (that is, it "points to") another block of memory, off goodness-knows-where, containing one or more chars. So, hihi[0] is the address of the first char of string A, hihi[1] is the address of the first char of string B.

If hihi doesn't point to an array, just a single pointer, then the tower block is a bungalow. Likewise if *hihi doesn't point to a string, just one char, then the long thin block is a square. You might ask, "how do I know how many floors the tower block has?". That's a big deal in C programming - usually either the function documentation would tell you (it might say "1", or "12", or "enough for the thing you're telling me to do", or else you would pass the number of floors as an extra parameter, or else the documentation would tell you that the array is "NULL terminated", meaning that it will keep reading until it sees the address/value NULL, and then stop. The main function actually does both the second and third thing - argc contains the number of arguments, and just to be on the safe side argv is NULL-terminated.

So, whenever you see a pointer parameter, you have to look at the documentation for the function to see whether it expecting a pointer to an array, and if so how big the array has to be. If you aren't careful about this, you will create a kind of bug called "buffer overflow", where a function is expecting a pointer to a large array, you give it a pointer to a small array, and it scribbles off the end of what you gave it and starts corrupting memory.

查看更多
Rolldiameter
4楼-- · 2020-07-09 10:39

Davos, are you in college? Are you a Computer Science major? One thing you might consider is taking an assembly language class (MIPS, x86). I was an Electrical Engineering major and I was required to take those kind of low level classes. One thing I observed was that having a clear understanding of the assembly language really helped me when I was started learning C++. In particular, it gave me a much clearer understanding of pointers.

Pointers and dereferencing are fundamental concepts at the assembly language level. If you are learning pointers for the first time, I find that in some ways "C" hides it a little bit too much and it actually becomes clearer at the assembly language level. Then you can take that lower level knowledge and see how the "C" language just puts some syntax on top of it.

Just a thought. Other than that, K&R is a great book as several people have mentioned and also, implementing some abstract data types like linked-lists can be useful, especially if you draw diagrams showing the memory layout, it can help to clarify the idea.

查看更多
Melony?
6楼-- · 2020-07-09 10:39

A somewhat unconventional suggestion: http://www.youtube.com/watch?v=Rxvv9krECNw

It's a lecture from Higher Computing 1 at my uni from last year. The first few minutes will be a bit useless (subject admin type stuff), but otherwise it's a really good explanation

查看更多
一纸荒年 Trace。
7楼-- · 2020-07-09 10:41

It sounds like you got the basics covered. I wouldn't jump to cheat-sheets until you've gone further over some literature. The reason to be careful when working with pointers is that they allow you to directly access specific memory addresses and if your code does that wrong things will break. An array will point to the first location and depending on the array type, you can access further locations in the array by working with a pointer of the same array-stored-value type.

I'd first understand variables, lvalue, rvalue and assignments, then pointers as variable types, then pointer dereferencing and further pointer operations. It would take quite a bit to elaborate on this and there are already many good references available.

You can find an introduction tutorial here (really detailed explanation). PDF Direct link.

查看更多
登录 后发表回答