我是C的新手,我在学习指针方面遇到了一些问题。我尝试了交换,这就是我可以用它们做的全部:)我知道每个变量在内存单元中都有自己的地址(这是我的讲师告诉我们的),每个变量的值都可以通过转到它的相关地址然后获得获取存储在其中的值。我见过一些函数头文件,例如:
int doSomething(char **hihi);
我的头很困惑。我知道指针也是一个变量,它只在地址信息中存储地址信息。我读到它们与数组密切相关
arr = &arr[0];
这就是我对指针的了解,我想知道如何加深对指针的看法。我搜索网,我找不到任何有用的备忘单覆盖指针。我也想知道为什么它们如此重要,有没有办法在不使用printf()
打印地址(p
)和值(\*p
)的情况下了解实际情况??
答案 0 :(得分:9)
打印地址和值是查看它们的合理方法。但是,如果你可以启动并运行调试器,那就更好了,因为你可以更快地跟踪指针,看着它们在你步进时改变,等等。
如果您熟悉Windows中的“快捷方式”或Linux文件系统中的软链接,那么就像您开始时一样,将指针视为另一个对象的快捷方式(软链接)可能会有所帮助(该对象是结构,内置类型,另一个指针等。)
快捷方式仍然是文件。它占用磁盘驱动器上自己的空间,它引用另一个文件,可以修改它以引用与以前不同的文件文件。类似地,C中的指针是占用内存的对象,包含另一个内存位置的地址,只需分配给它就可以更改为包含不同的地址。
一个区别是,如果双击一个快捷方式,它的行为就像双击它所指向的东西一样。指针不是这种情况 - 您必须使用“*”或“ - >”明确取消引用指针为了访问它指向的东西。另一个不同之处在于指向指向C语言的指针是很常见的。
至于行话,你不得不学习它。 “int doSomething(char ** hihi)”表示“一个名为doSomething的函数,它返回一个整数,并将一个指向char的指针作为参数”。关键的一点是“char ** hihi
”表示“指向指针指向char的指针。我们将指向指针指向char hihi”。你说hihi的“类型”是char **,并且* hihi的“类型”(你取消引用指针时得到的)是char *,** hihi的类型是char。
经常在C中,指向char的指针意味着一个字符串(换句话说,它是一个指向NUL终止数组中第一个字符的指针)。因此,“char *”通常意味着“字符串”,但它不必。它可能只是指向一个char的指针。有点像Windows中1字节文件的快捷方式(好吧,无论如何都是FAT32),指向C中的char的指针实际上比它所指向的更大: - )
同样,char **通常不仅指向一个字符串指针的指针,而且指一个字符串指针数组。它可能没有,但如果确实如此,那么下面的小图片可能有所帮助:
hihi ____ ____ ________ _________ _______ |____| -----> |____| *hihi ---> |___A____| |___B_____| |___C___| |____| *(hihi+1) ------------------^ ^ |____| *(hihi+2) ---------------------------------| | ...| etc.
hihi指向塔块的努力,这是我表示一系列指针的方式。正如你已经注意到的那样,我可以用hihi [0]代替* hihi,hihi [1]来代替*(hihi + 1),依此类推。
这是一个连续的内存块,它的每个指针大小的块包含另一个内存块的地址(即,它“指向”),offness-know-where,包含一个或多个chars 。因此,hihi [0]是字符串A的第一个字符的地址,hihi [1]是字符串B的第一个字符的地址。
如果hihi没有指向一个阵列,只有一个指针,那么塔楼就是一个平房。同样,如果* hihi没有指向一个字符串,只有一个字符,那么长细块就是一个正方形。你可能会问,“我怎么知道塔楼有多少层?”。这在C编程中是一个大问题 - 通常是函数文档会告诉你(它可能会说“1”,或“12”,或“足够你告诉我要做的事情”,否则你会通过作为额外参数的楼层数,或者文档会告诉你数组是“NULL终止”,这意味着它将继续读取,直到它看到地址/值为NULL,然后停止。主函数实际上同时执行第二和第三件事 - argc包含参数的数量,和只是为了安全起见argv是以NULL结尾的。
因此,每当你看到一个指针参数时,你必须查看该函数的文档,看它是否期望指向一个数组的指针,如果是这样,那么该数组必须有多大。如果你不小心这个,你会创建一种称为“缓冲区溢出”的错误,其中一个函数期望一个指向一个大数组的指针,你给它一个指向一个小数组的指针,然后它会乱写一下你给它的东西,并开始破坏记忆。
答案 1 :(得分:6)
我认为这是经典书籍比大多数在线资源更有用的地方。如果你能得到一份副本,请非常仔细地阅读 The C Programming Language (a.k.a K& R)。如果您想了解更多信息,请选择专家C编程:深层秘密(只需谷歌)。
答案 2 :(得分:2)
指针就是一个地方。
数组是一组连续的地方。
一个地方总有价值。 (可能是剩下的垃圾)。
每个变量都有一个地方。
对于指针变量,其位置的值是一个位置。
这就像寻宝一样。 “在邮箱13中查找一条说明哪个邮箱中包含生日卡的说明。”
如果邮箱13中包含一条显示“13”的便条,那么您的生日卡将会很长时间! (这是由圆形指针引用引起的错误。; - )
答案 3 :(得分:0)
虽然阅读K& R可能是最好的选择,但我会尝试让它更清晰:
指针本身就是一个变量。但它不存储值,而只存储地址。可以把它想象成一个索引:就像你的地址簿中你要搜索的东西的索引(比如某个名字的电话号码)一样,它指向信息的存储位置。在您的地址簿中,它可能会说“请查看第23页以查找Joe的电话号码”。在指针的情况下,它只是简单地说“查看内存地址1234以检索我指向的信息”。由于指针值本身只是一个内存地址,你可以使用它进行算术运算 - 比如添加值(这与访问数组的元素相同:如果指针指向数组,则地址跟随指针的地址)指向将访问数组中的下一个元素)。
您的示例函数int doSomething(char *hihi)
将指向您在调用它时传递的内存地址。如果您想要传递更大量的数据(而不是复制数据(在void blah(int a)
之类的函数中使用值a),这非常有用)您只复制其位置。
我在上面遗漏了一些细节,但我希望它至少能给你一些基本的了解。我强烈建议阅读K& R或关于该主题的类似书籍。
答案 4 :(得分:0)
听起来你已经掌握了基础知识。在你进一步了解一些文献之前,我不会跳到作弊表。 使用指针时要小心的原因是它们允许您直接访问特定的内存地址,如果您的代码执行错误,则会破坏。数组将指向第一个位置,并且根据数组类型,您可以通过使用相同数组存储值类型的指针来访问数组中的其他位置。
我首先理解变量,左值,右值和赋值,然后指针作为变量类型,然后是指针解引用和进一步的指针操作。这需要花费很多时间来详细说明,并且已经有很多很好的参考资料。
您可以找到介绍教程here(非常详细的解释)。 PDF Direct link
答案 5 :(得分:0)
/* 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 */
答案 6 :(得分:0)
指针和解除引用是汇编语言级别的基本概念。如果你是第一次学习指针,我发现在某种程度上“C”隐藏了一点点,它实际上在汇编语言层面变得更加清晰。然后你可以掌握较低级别的知识,看看“C”语言是如何在它上面添加一些语法的。
只是一个想法。除此之外,K& R是一本很好的书,正如几个人所提到的那样,实现一些抽象数据类型如链接列表也很有用,特别是如果你绘制显示内存布局的图表,它可以帮助澄清这个想法。
答案 7 :(得分:0)
恕我直言,“获取”指针的最佳方法是进行一些汇编语言编程。一旦你习惯于考虑原始寄存器内容(数据和地址之间没有真正的区别,除了你如何使用它们)和加载存储指令,C的指针类型将更有意义(和你的欣赏C会为你做的事情会有很大改善。)
答案 8 :(得分:0)
答案 9 :(得分:0)
上面给出了许多好的答案。其他一些见解是指针始终是无符号整数类型。它在内存中指向的对象或变量可以是任何类型。
在32位操作系统中,整数是一个4字节的数字,必须在
范围内0<指针值< (2 ^^ 32)-1
在64位操作系统中,整数是一个8字节的数字,必须在
范围内0<指针值< (2 ^^ 64)-1
指针值= 0被解释为一个名为NULL的特殊标志值,表示该指针未指向可用变量。
指针用于间接。 CPU中的一些寄存器充当指针,例如程序计数器(PC)和地址寄存器。
答案 10 :(得分:-1)
您是否阅读过K&R?如果你还没有,我会说那是你应该开始的地方。
答案 11 :(得分:-1)
答案 12 :(得分:-1)
有点不同寻常的建议:http://www.youtube.com/watch?v=Rxvv9krECNw
这是去年我在大学的高等计算1的讲座。前几分钟会有点无用(主题管理类型的东西),但否则这是一个非常好的解释