如何在C中处理指针?

我是C的新手,我在学习指针方面遇到了一些问题。 我尝试了交换,这就是我可以用它们做的全部:)我知道每个变量在内存单元中都有自己的地址(这是我的讲师告诉我们的),每个变量的值都可以通过转到它的相关地址来获得获取存储在其中的值。 我见过一些函数头文件,例如:

int doSomething(char **hihi); 

我的头很困惑。 我知道指针也是一个变量,它只在地址信息中存储地址信息。 我读到它们与数组密切相关

 arr = &arr[0]; 

这就是我对指针的了解,我想知道如何加深我对指针的看法。 我搜索网,我找不到任何有用的备忘单覆盖指针。 而且我也想知道为什么它们如此重要并且有没有办法在不使用printf()打印它们的地址( p )和值( \*p )的情况下理解实际发生了什么?

打印地址和值是查看它们的合理方法。 但是,如果您可以启动并运行调试器,那就更好了,因为您可以更快地关注指针,观察它们在您步进时的变化,等等。

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

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

一个区别是,如果双击快捷方式,它的行为就像双击它指向的东西一样。 指针不是这种情况 – 你总是必须用“*”或“ – >”明确地取消引用一个指针,以便访问它所指向的东西。 另一个不同之处在于指向指向C中指针的指针是很常见的。

至于行话,你不得不学习它。 “int doSomething(char ** hihi)”表示“一个名为doS​​omething的函数,它返回一个整数,并将一个指向char的指针作为参数”。 关键的一点是“ char ** hihi ”的意思是“指针指向char的指针。我们将指向指针指向char hihi”。 你说hihi的“类型”是char **,并且* hihi的“类型”(当你取消引用指针时得到的)是char *,** hihi的类型是char。

经常在C中,指向char的指针意味着一个字符串(换句话说,它是一个指向NUL终止数组中第一个字符的指针)。 因此,“char *”通常意味着“字符串”,但它不必。 它可能只是指向一个char的指针。 有点像Windows中1字节文件的快捷方式(好吧,无论如何都是FAT32),指向C中的char的指针实际上比它指向的更大:-)

同样,char **通常不仅指向一个字符串指针的指针,而且指一个字符串指针数组。 它可能没有,但如果确实如此,那么下面的小图片可能会有所帮助:

日冰
  ____ ____ ________ _________ _______
 | ____ |  -----> | ____ |  * hihi ---> | ___ A ____ |  | ___乙_____ |  | ___ ___Ç|
                 | ____ |  *(hihi + 1)------------------ ^ ^
                 | ____ |  *(hihi + 2)--------------------------------- |
                 |  ... | 等等

hihi指向塔块的努力,这是我表示一系列指针的方式。 正如你已经注意到的,我可以用hihi [0]代替* hihi,hihi [1]来代替*(hihi + 1),依此类推。

这是一个连续的内存块,它的每个指针大小的块包含另一个内存块的地址(即,它“指向”),包含一个或多个字符的goodness-know-where。 所以,hihi [0]是字符串A的第一个字符的地址,hihi [1]是字符串B的第一个字符的地址。

如果hihi没有指向一个arrays,只有一个指针,那么塔楼就是一个平房。 同样,如果* hihi没有指向一个字符串,只有一个字符,那么长细块就是一个正方形。 你可能会问,“我怎么知道塔楼有多少层?”。 这在C编程中是一个大问题 – 通常是函数文档会告诉你(它可能会说“1”,或“12”,或“足够你告诉我要做的事情”,否则你会通过作为额外参数的楼层数,或者文档会告诉你数组是“NULL终止”,这意味着它将继续读取,直到它看到地址/值为NULL,然后停止。主函数实际上同时执行第二和第三件事 – argc包含参数的数量, 并且为了安全起见,argv是以NULL结尾的。

因此,每当您看到指针参数时,您必须查看该函数的文档,以查看它是否期望指向数组的指针,如果是,那么该数组必须有多大。 如果你不小心这个,你会创建一种叫做“缓冲区溢出”的错误,其中一个函数期望一个指向一个大数组的指针,你给它一个指向一个小数组的指针,然后它会乱写一下你给它的东西,并开始破坏记忆。

我认为这是经典书籍比大多数在线资源更有用的地方。 如果您能获得副本,请非常仔细地阅读C编程语言 (又名K&R)。 如果你想了解更多,请选择专家C编程:深层秘密 (只需谷歌)。

指针是一个地方。

数组是一组连续的地方。

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

每个变量都有一个位置。

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

这就像寻宝一样。 “在邮箱13中查找一条说明哪个邮箱中包含生日卡的说明。”

如果邮箱13中包含一条显示“13”的便条,那么您的生日卡将会很长时间到来! (这是由圆形指针引用引起的错误。;-)

虽然阅读K&R可能是最好的选择,但我会尝试让它更清晰一些:

指针本身就是一个变量。 但它不存储值,而只存储地址。 可以把它想象成一个索引:就像在你的地址簿中一样,你要搜索的东西的索引(比如某个名字的电话号码)指向信息存储的位置。 在您的地址簿中,它可能会说“请查看第23页以查找Joe的电话号码”。 在指针的情况下,它只是简单地说“查看内存地址1234以检索我指向的信息”。 由于指针值本身只是一个内存地址,你可以使用它进行算术运算 – 比如添加值(这与访问数组的元素相同:如果指针指向数组,则指针跟随指针的地址)指向将访问数组中的下一个元素)。 您的示例函数int doSomething(char *hihi)将指向您在调用它时传递的内存地址。 如果要传递更大量的数据(而不是复制数据(在void blah(int a)等函数中使用值void blah(int a) ,则此选项非常有用,您只需复制其位置。

我在上面遗漏了一些细节,但我希望它至少能给你一些基本的了解。 我强烈建议阅读K&R或关于该主题的类似书籍。

 /* 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 */ 

达沃斯,你在大学吗? 你是计算机科学专业吗? 您可以考虑的一件事是使用汇编语言类(MIPS,x86)。 我是一名电气工程专业的学生,​​我被要求参加那些低级课程。 我观察到的一件事是,当我开始学习C ++时,清楚地理解汇编语言确实对我有所帮助。 特别是,它让我对指针有了更清晰的理解。

指针和解除引用是汇编语言级别的基本概念。 如果你是第一次学习指针,我发现在某些方面“C”隐藏了一点点,它实际上在汇编语言级别变得更加清晰。 然后你可以掌握较低级别的知识,看看“C”语言如何在它之上加上一些语法。

只是一个想法。 除此之外,K&R是一本很好的书,正如几个人所提到的那样,实现一些抽象数据类型如链接列表也很有用,特别是如果你绘制显示内存布局的图表,它可以帮助澄清这个想法。

恕我直言“获取”指针的最佳方法是进行一些汇编语言编程。 一旦你习惯于考虑原始寄存器内容(数据和地址之间没有真正的区别,除了你如何使用它们)和加载存储指令,C的指针类型将更有意义(和你的欣赏C为你做什么将会大大改善)。

上面给出了许多好的答案。 其他一些见解是指针始终是无符号整数类型。 它在内存中指向的对象或变量可以是任何类型。

在32位操作系统中,整数是一个4字节的数字,必须在该范围内

0 <指针值<(2 ^^ 32)-1

在64位操作系统中,整数是一个8字节的数字,必须在该范围内

0 <指针值<(2 ^^ 64)-1

指针值= 0被解释为一个名为NULL的特殊标志值,表示该指针不指向可用变量。

指针用于间接。 CPU中的某些寄存器充当指针,例如程序计数器(PC)和地址寄存器。

如果你真的想了解指针,你需要一个很好的大学讲座。

我见过的最好的就是这一个 。

没有别的比较。

另请参阅图灵讲座。 它做得很好。

听起来你已经掌握了基础知识。 在你进一步了解一些文献之前,我不会跳到作弊表。 使用指针时要小心的原因是它们允许您直接访问特定的内存地址,如果您的代码执行错误,则会破坏。 数组将指向第一个位置,并且根据数组类型,您可以通过使用相同array-stored-value类型的指针来访问数组中的其他位置。

我首先理解变量,左值,右值和赋值,然后指针作为变量类型,然后指针解引用和进一步的指针操作。 需要花费很多时间来详细说明这一点,并且已经有很多很好的参考资料。

你可以在这里找到介绍教程(非常详细的解释)。 PDF直接链接 。

你读过K&R吗? 如果你还没有,我会说那是你应该开始的地方。

以下是教授C指针如何工作的一些基本解释 。

一个有点不同寻常的建议: http : //www.youtube.com/watch?v = RMvv9krECNw

这是去年我在大学的高等计算1的讲座。 前几分钟会有点无用(主题管理类型的东西),但否则这是一个非常好的解释