如何在C语言中接近指针?

如何在C语言中接近指针?,c,pointers,C,Pointers,我是C语言的新手,在学习指针方面有一些问题。我做过交换实验,这就是我能做的:)我知道每个变量在内存单元中都有自己的地址(这是我的讲师告诉我们的),每个变量的值都可以通过转到其关联的地址,然后获取存储在其中的值来获得。我见过一些函数头,例如: int doSomething(char **hihi); 我的脑袋好乱。我知道指针也是一个变量,它只在内存单元中存储地址信息。我读到它们与数组密切相关 arr = &arr[0]; 这就是我对指针的全部了解,我想知道如何才能加深对指针的理解。我

我是C语言的新手,在学习指针方面有一些问题。我做过交换实验,这就是我能做的:)我知道每个变量在内存单元中都有自己的地址(这是我的讲师告诉我们的),每个变量的值都可以通过转到其关联的地址,然后获取存储在其中的值来获得。我见过一些函数头,例如:

int doSomething(char **hihi);
我的脑袋好乱。我知道指针也是一个变量,它只在内存单元中存储地址信息。我读到它们与数组密切相关

arr = &arr[0];

这就是我对指针的全部了解,我想知道如何才能加深对指针的理解。我在网上搜索,找不到任何有用的包含指针的备忘单。我还想知道为什么它们如此重要,有没有办法不使用
printf()
打印它们的地址(
p
)和值(
\*p
)?

我认为这是经典书籍比大多数在线资源更有用的地方。如果你能得到一份副本,请非常仔细地阅读C编程语言(又称k&R)。如果你想知道更多,就去找C编程专家:深层秘密(只需谷歌一下)

指针是一个位置

数组是一组连续的位置

一个地方总是有价值的。(可能是吃剩的垃圾)

每个变量都有一个位置

对于指针变量,其位置处的值是一个位置

这就像寻宝。“在邮箱13中查找一张便条,告知您哪个邮箱包含您的生日卡。”


如果邮箱13上有一张写着“13”的便条,那么你的生日卡就要等很久了!(这是由循环指针引用引起的错误。-)

您读过了吗?如果你没有,我会说这是你应该开始的地方。

一个有点非传统的建议:


这是我大学的高等计算1去年的一次讲座。前几分钟会有点没用(主题管理员类型的东西),但除此之外,这是一个很好的解释

打印地址和值是查看它们的合理方式。但如果你能启动并运行一个调试器,那就更好了,因为你可以更快地跟踪指针,观察它们随着你的脚步而变化,等等

如果您熟悉Windows中的“快捷方式”或linux文件系统中的软链接,那么在您刚开始学习时,将指针视为指向另一个对象(无论该对象是结构、内置类型还是另一个指针等)的快捷方式(软链接)可能会有所帮助

快捷方式仍然是一个文件。它在磁盘驱动器上占用自己的空间,它引用另一个文件,并且可以修改它以引用与以前不同的文件。类似地,C中的指针是一个对象,它占用内存,包含另一个内存位置的地址,只需分配给它,就可以更改为包含不同的地址

一个区别是,如果你双击一个快捷方式,它的行为就像你双击了它指向的东西一样。指针的情况并非如此——为了访问指针所指向的对象,您总是必须显式地用“*”或“->”取消对指针的引用。另一个区别是,在C语言中,有指向某些东西的指针是很常见的

至于行话,不幸的是,你必须学会。“int doSomething(char**hihi)”表示“一个名为doSomething的函数,它返回一个整数,并将指向char的指针作为参数”。关键的一点是“
char**hihi
”意味着“指向char的指针。我们将调用指向char的指针hihi”。你说hihi的“类型”是char**,而*hihi的“类型”是char*,而**hihi的类型是char*

在C语言中,指向字符的指针通常意味着字符串(换句话说,它是指向以NUL结尾的数组中的第一个字符的指针)。通常情况下,“char*”表示“string”,但并不一定要这样。它可能只是指向一个字符的指针。有点像Windows中一个1字节文件的快捷方式(好吧,反正是FAT32),C中指向字符的指针实际上比它指向的东西大:-)

类似地,char**通常不仅表示指向一个字符串指针的指针,还表示指向一个字符串指针数组的指针。可能没有,但如果有,下面的小图片可能会有所帮助:

hihi ____ ____ ________ _________ _______ |____| -----> |____| *hihi ---> |___A____| |___B_____| |___C___| |____| *(hihi+1) ------------------^ ^ |____| *(hihi+2) ---------------------------------| | ...| etc. 嗨 ____ ____ ________ _________ _______ |____|--->| | | | | | | | | | | | | | | | | | | | | | C___| |____|*(hihi+1)-------------------^ |____|*(hihi+2)---------------------------------| |等等。 hihi指向塔块,这是我表示指针数组的方式。正如您已经注意到的,我可以用hihi[0]代替*hihi,用hihi[1]代替*(hihi+1)等等

这是一个连续的内存块,每个指针大小的内存块都包含(即它“指向”)另一个内存块的地址,不知道在哪里,包含一个或多个字符。因此,hihi[0]是字符串A的第一个字符的地址,hihi[1]是字符串B的第一个字符的地址

如果hihi不指向数组,只指向一个指针,那么塔楼就是平房。同样,如果*hihi不指向字符串,只指向一个字符,那么长而细的块就是一个正方形。你可能会问,“我怎么知道塔楼有多少层?”。这在C编程中是一个大问题——通常函数文档会告诉您(它可能会说“1”,或“12”,或“足够您告诉我做的事情了”),或者您会将楼层数作为一个额外参数传递,或者文档会告诉您数组是“以NULL结尾的”,这意味着它将一直读取,直到看到地址/值为NULL,然后停止
/* Given a string of characters like this one: */
char *string = "Hello!\n";

/* Memory will contain something like:
0x00100 'H'
0x00101 'e'
0x00102 'l'
0x00103 'l'
0x00104 'o'
0x00105 '!'
0x00106 '\n'
0x00107 '\0'
*/

/* And the program code will say: */
string=0x00100;

/* C doesn't really have arrays */
char c=string[3];
/* is just syntactic sugar for: */

char c=*((char*)((void*)string + 3 * sizeof(char)));
/* ie. 0x00100 + 3 * 1 */
/* ie. 0x00103 */
/* and * dereferences 0x00103, this means char_in(0x00103) */

/* When you pass a pointer you are actually passing the value
   of the memory position */

int a;          /* allocates space for a random four byte value in
                   0x00108 */
scanf("%d",&a); /* &a = 0x00108 scanf now knows that it has to store
                  the value in 0x0108 */

/* Even if you declare: */
int b[23];
/* b will be just a pointer to the beginning of 23 allocated ints.
   ie. 0x0010C */

/* pointer arithmetic is different from normal types in that: */
b++;
/* is actually: */
b+=4; /* b+=1*sizeof(int); */
/* So pointers in C work more like arrays */