C语言指针是纸老虎,看5个方面
我们来看看5个维度。不过在我们说话之前,我先写了一个程序,其中包含了指针的“两个自体和三个其他”维度,然后一一解释了每个维度的含义。看看是否会出现这种情况。
在大多数使用指针的场景中,这5个维度应该足以帮助你理解。但是,在一些使用指针的特殊场景下,5维方法可能就帮不了你了。
长文提前警告,如果你不耐烦,可以将这篇文章加入书签,有时间再读一遍。
1。程序代码
1.1。代码
Instance
#include
int main(void)
{
int *pInt = NULL;int *pInt = NULL;: 0X %x\n", &pInt);
//printf("指针变量值 pInt: 0X%x\n", pInt);
int para = 1;
printf("地址para 变量: 0X%x\n", ¶);
printf("Para 变量值: 0X%x\n ", para);
pInt = ¶
printf("Para 变量值指针 pInt : 0X%x\n", pInt);
printf("指针变量值 pInt 另一个值: 0X%x \n", *pInt);
int arr_int[2] = {1, 2 };
pInt = arr_int;
printf("arr_int 第一个元素 arr_int[0 ] 地址:0X%x\n", pInt);
printf("arr_int 第二个元素 arr_int ] 的地址是: 0X% x\n", pInt + 1);
double *pDouble = NULL;
double arr_double[2] = {1.1, 2.2}; = arr_double printf("arr_double第一个元素 arr_d ouble[0] 的地址为:0X %x\n", pDouble);
printf("arr_double arr_double[1] 第二个元素的地址为: 0X% x\n", pDouble + 1 );
返回0;
}
运行结果如下:我文章中的
当我理解一些东西时,我喜欢用一个非常简单的程序来解释。所以那些认为你应该用圣经这样的程序来解释你的观点的人,或者那些鄙视低级程序的人,不要忘记我^_^。
2.2。 Para int 类型变量
在程序中:
int para = 1; printf("变量para自己的地址是: 0X%x\n", ¶); printf("变量para自己的值是: 0X%x\n", para);
定义了para变量,它有自己的数据值和自己的存储地址。这一切都很容易理解。从运行结果来看,para变量的数据值为十六进制的“0X1”,地址为十六进制的“0X22feb4”。也就是说,在内存中,从地址“0X22feb4”开始的存储空间有4个字节存储数据值“0X1”。在我的机器上,int变量占用4个字节,在你的机器上可能有所不同。
大家都能轻松理解int类型变量para。接下来我画一个示意图来展示变量在内存中是如何存储的,如下:
先从“两个自己,三个别人”的概念开始。
2. 两个和另外三个
“两个和另外三个”,扩展起来就是:自己的地址、自己的值、值、其他地址、其他类型。
2.1。地址吉
2.1.1 “地址吉”的概念
“地址吉”是“自己的地址”的缩写。作为变量,指针 pInt 与变量 int para 一样,也必须存储在内存中的存储位置中。这个存储空间也会有一个起始地址,即指针变量pInt也会有自己的地址。上面提到了para变量的地址是“0X22feb4”,那么指针变量pInt的地址是多少呢?
2.1.2 获取“地址”
我们都知道“&”是获取地址的运算符。程序中:
printf("指针变量pInt自己的地址是: 0X%x\n", &pInt);
使用“&”来获取指针变量 pInt 的地址。从运行结果来看,指针变量pInt的地址为“0X22feb8”。在我的机器上,指针变量pInt也占用4个字节。因此,指针变量pInt被存储在起始地址“0X22feb8”开始的4字节空间中。 ?添加pInt指针变量的“地址”,表示pInt指针变量在内存中的存储方式。
“吉吉”,就是这个意思。你看,没有什么是那么困难的!
2.2 自身价值
2.2.1 “自身价值”的概念
“自身价值”是“自身数据价值”的简称。作为变量,pInt 指针与 para 变量一样,也有自己的数据值。
2.2.2 获取“自己的值”
上面提到了para变量的数据值为“1”,那么指针变量pInt的数据值是多少。程序中:
pInt = ¶ printf("指针变量pInt自己的值是: 0X%x\n", pInt);
我使用“&”运算符将para变量的地址值赋给指针变量pInt,并使用printf返回指针变量pInt的数据值。从运行结果来看,指针变量pInt的数据值为“0X22feb4”。我们再看一下。 para变量的地址也是“0X22feb4”。所以,这条语句
pInt = ¶
的本质就是将变量para的地址赋值给指针变量pInt的值,从而将指针变量pInt绑定到变量para上。一起。
如《我的地址》中提到的,pInt指针的数据值存储在以地址“0X22feb8”开始的4字节内存中,也就是说内存以地址“0X22feb8”开始,下面的4 bytes 用于存储数据值“0X22feb4”。
2.2.3 如何写“自己的值”的代码
代码中写了如何写指针变量pInt的“自己的值”的代码。常见的代码编写方式是
pInt;
,部分代码的编写方式是:
pInt + N; pInt - N;
编写方式是在“自值”pInt 中加上数字 N 或减去数字 N。这一点在我们谈论“其他类型”属性时会提到。还有一种写法:
pIntA - pIntB;
这种写法是指用“自己的值”来减去两个指针变量。
2.2.4 示意图
现在继续添加上面的原理图,并添加指针变量pInt 的值。
所以,一般来说,指针变量pInt的“自身值”就是数据值本身;对于其他int类型变量,它是地址。
2.3 其他地址
2.3.1 “其他地址”的概念
“其他地址”的概念是指“他人的地址”。事实上,上面提到自我价值时,并没有明确提到“其他地址”的概念。
2.3.2 获取“其他地址”
整数变量para存储在从内存地址“0X22feb4”开始的4个字节中。在程序中,我通过
pInt = ¶
将para变量的地址赋值给pInt指针变量,从而将pInt指针变量和para变量绑定在一起。更重要的是,“别人的地址”被赋值给了指针变量pInt的“自己的值”。这里,“他人地址”中的“他”指的是para变量,“他人地址的地址”。 “地址”指的是para变量的地址。记住,你看,“其他地址”和“自己的值”与数据值相同,所以,你已经知道发生了什么了吗?
很多教科书都说“指针是一个地址变量,它存储着另一个变量的地址”。显然,这意味着“其他地址”维度中的数据值与“自身值”维度中的数据值相同。课本上并没有说清楚。
2.3.3 示意图
我们再添加一个示意图,这次添加“另一个地址”的概念。
2.4 其他值
2.4.1 “其他值”的概念
“其他值”是指“其他人的数据值”。
2.4.2 获取“其他值”
在程序中,我通过
pInt = ¶
将para变量的地址赋值给pInt指针变量的“自己的值”,从而将pInt指针变量绑定到para 变量。设置在一起。此时,“他人的数据值”的“he”指的是para变量,“他人的数据值”的“数据值”指的是para变量的数据值“1”。在程序中,我使用
printf("指针变量pInt的他值是: 0X%x\n", *pInt);
,即在指针变量pInt前面添加“*”,返回指针变量的“其他值”。从运行结果来看,是“0X1”。记住,你看,指针变量pInt的“其他值”与para变量的数据值相同。你可知道?想不通吗?一直在看!
2.4.3 “其他值”代码写法
代码写法在代码中经常见到,比如*pInt怎么写,什么意思?事实上,它计算的是指针变量pInt“他值得”!
如何写:*(pInt + 1), *pInt + 1, pInt[1]?
*(pInt + 1):如果pInt + 1被认为是另一个指针,比如
int *pTemp = pInt + 1;
,那么*(pInt + 1)的计算意味着指针变量pTemp的“另一个值”;
*pInt + 1:这是使用pInt的“其他值”加1;
pInt[1]:怎么样?事实上,它是*(pInt + 1)。
2.4.4 示意图
继续在上图中添加,这次添加“其他值”的概念:
2.5 其他类型
2.5.1 “其他类型”的概念 ”,是“别人”的缩写。在程序中,我们看到在声明指针变量pInt时,是这样写的: 指针变量pInt前面的“int”并不代表指针变量pInt的“值”是数据。该值是int类型;相反,它意味着指针变量 pInt 的“另一个值”是“int”类型的数据值。这里指针变量pInt的“其他值”是变量para的数据值“0X1”。因此,指针变量pInt前面的“int”表示数据值“0X1”是“int”类型。 换句话来说,声明指针时的类型是用来修改“另一个值”的,而不是“你自己的值”。 再看一下,声明para变量时: para变量前面的“int”表示para变量的类型是整数,此时的“int”就是“自变量” type" for para",意思是“类型本身”。声明时唯一的指针类型是“other type”,即“其他类型”。 因为“其他类型”是用来修饰“其他值”的。” ,在声明指针时添加这个“其他类型”有什么意义?一直在看! 程序中,如下一段代码: 我将整型数组arr_int的地址赋给指针变量pInt,那么pInt的“地址”没有改变,仍然是0X22feb8,但是“值”的变化。参数变量。现在是“0X22feac”,这是 arr_int 数组的第一个元素的地址。也就是说,指针变量pInt的“地址”不会改变,但“值”可以。 现在让我们看看“pInt”和“pInt + 1”之间的区别。它使用 pInt 的“值”来执行操作。从运行结果来看,此时pInt的“值”为“0X22feac”,pInt+1的“值”为“0X22feb0”。你有没有注意到,两者之间的差别正好是4个字节,而一个“Int”数据类型也正好占用了4个字节。 你可能会认为pInt + 1使用的是“自身值”加1,所以应该是“0X22feac + 1”=“0X22fead”。为什么不?这种情况发生在指针变量 pInt 的“其他类型”上。 “其他类型”的意思,用口语来说就是:“我说pInt,兄弟,另一个值是int类型的数据值,以后如果用自己的值+1,+2,或-1、-2,但别傻了,只加1个字节或2个字节,或者只减1个字节或2个字节。int类型占用4个字节,所以需要以4个字节为单位加上1*4个字节或者2*4个字节,或者减去1*4个字节或者2*4个字节,你知道吗?无论如何,pInt + N 中的 N 可以是正数或负数。 “自值”,pInt + 2 表示“自值”加上 8 * 2 = 16 个字节,就是这个意思。 我在程序中再举一个例子来说明这个“另一种类型”。如下: 这次我们声明了一个指针变量pDouble,“其他类型”是“double”类型,“它自己的值”是arr_double数组的地址,“其他值”是数据值。数组元素 arr_double[0] 的“1.1”。在机器中,double类型占用8个字节,所以pDouble + 1使用pDouble“值”加1 * 8字节,pDouble + 2是pDouble的“自己的值”加2 * 8 = 16个字节,pDouble - 1是pDouble - 1 pDouble 的“自身值”减去 1 * 8 个字节,pDouble - 2 就是 pDouble 的“自身值”减去 2 * 8 = 16 个字节,我是个好孩子!小伙伴们可以根据跑步结果自己算一下吧? 是时候总结一下了。 我做了一个指针变量声明: pType有5个维度,即: pType = (自己的地址,自己的值,其他地址,其他值,其他类型); 作为变量,指针变量pType也有自己的地址。编写代码的常见方法是“&pType”。 地址在公共程序中不常使用。如果使用,则包含“引用指针”其他主题,本文不再讨论; 指针变量 pType 作为变量,它也有自己的数据值,代码怎么写就是“pType”。 您还可以对值执行加法和减法运算。常见的代码编写方式有“pType + N”、“pType - N”、“pType2 - pType1”等。 指针变量 pType 的值,除了表示自己的数据值外,还表示与 pType 绑定的“type”类型变量的地址。一般来说,指针变量pType的“自身值”和“其他地址”是相同的数据值。 将类型type的变量绑定到pType的一般方法是:pType = &variable; type类型变量与pType绑定在一起后,指针变量pType可以通过一些编写代码的方法获取type类型变量的值,即“其他价值”。常见的代码编写方式有:“*pType”、“pType->”等。 代码怎么写:“*(pType + N)”、“*(pType - N)”、“pType [N]”也是获取的“其他值”,但需要特别说明: pType + N 可以认为是: " *(pType + N) "实际上计算的是指针变量pTemp的“其他值”。 " *(pType - N) " 会更容易让你理解; “pType[N]”实际上是“*(pType + N)”,所以记住它即可。 声明pType指针变量时,前面的“类型”不是用来修改pType的“自己的值”,而是用来修改“其他值”。换句话说,“type”并不意味着pType的“自己的值”是type类型的数据值,而是pType的“其他值”是type类型的数据值。 代码中“其他类型”的作用主要是在计算“pType + N”和“pType - N”时为pType加减( N * sizeof(type) )个字节。 指点总是让人头晕,而且可能会让人在这五个维度中的一个或多个维度上头晕。彻底了解这5个维度。指针只是一只纸老虎。 讲解完5个维度,怎么能不开始练习呢?这里有一些练习,都与指针有关,可能会让初学者头晕。我用这5个维度来解释这个问题。看看它是多么容易! 4.1.1 程序 第一个非常常见的程序示例是查找数组元素的数量。程序如下: #include int main(void) { = int *p = int LL; in LL ; arr[3]= {1, 2, 3}; pArr = arr; printf("数组元素:"); = 对于 0 索引 { printf("%d ", pArr[index]); } ♽ ♽ ♽♽♽; for(int 索引 = 0;索引 sum = sum + *(pArr + 索引); } printf("数组元素个数为:%d\n", number); return 0; } 这个程序非常简单。首先返回数组的所有元素,然后计算数组所有元素的总和。结果如下: 4.1.2 “两个自己,三个别人”的解释 4.1.2.1 输出数组元素 输出数组元素时,代码如下: ♼同理as 这里,“自身值”和“其他类型”用于执行附加操作,“其他值”用于检索数组元素。 “自己的值”:第一个代码将数组名arr中的数据值分配给pArr的“自己的值”。数组名arr的数据值是多少?就是元素arr[0]的地址,对吧!那么pArr的值也是arr[0]的地址,对吧!这样,pArr就绑定到了arr[0]。 至于(pArr + index)的含义,你可以把它看成是一个间接指针变量,pTemp: 也就是说,pArr + index实际上是一个pTemp指针,只不过这个pTemp是有值的。是 pArr 的值加上索引 * sizeof(int) 字节。 “其他类型”:pArr的其他类型为“int”类型,pArr+index,在pArr原值的基础上增加了多少字节? pArr的另一种类型是int类型,同样pArr + index表示pArr的值加上index * sizeof(int)字节! pArr:可以写成pArr + 0,表示增加0 * 4 = 0个字节。此时pTemp的值就是arr[0]的地址; pArr + 1:增加1 * 4 = 4个字节,此时pTemp的值为arr[1]的地址; pArr + 2:即加上2 * 4 = 8字节,此时pTemp的值为arr[2]地址; 这样索引pArr+就遍历了数组所有元素的地址。 你会发现pTemp的值发生了变化; pArr 的值和地址不变。 “其他值”:由于pArr + index可以传递所有数组元素的地址,那么使用*(pArr + index),即*pTemp,可以得到其他pTemp值,所以Variable为所有数组元素的值! ?清除! pArr + index 仍然使用pArr的值进行加法,得到临时指针pTemp的值。这个pTemp值是每个数组元素的地址; 然后使用*(pArr + inedx),即*pTemp,从临时指针pTemp中得到另一个值,即每个元素的值。 最后,将每个 pTemp 值相加即可计算数组元素的数量。? ! 指针数组是指针和数组的组合。对于初学者来说会很难理解。指针数组是一个比较大的话题。相关概念请阅读通用C语言教材。这里我们只用“二自三他”的概念来解释程序中指针的概念。 4.2.1 程序 指针数组,我举个例子如下: #include '{void) cah *arr[3] = {"abc", "def", "ghi"}; char *pArr = arr[0]; printf("字符串数组 arr 中的每个字符串:"); for ( int index = 0;index { " printf("\n"); printf("字符串数组 arr 中字符串的第一个元素是: "); for(int index = 0; index return 0; } 运行结果如下: 4.2.2 “两人三人”的解释” int *pInt = NULL;
int para = 1;
int arr_int[2] = {1, 2};
pInt = arr_int;
printf("arr_int第一个元素arr_int[0]的地址是: 0X%x\n", pInt);
printf("arr_int第二个元素arr_int[1]的地址是: 0X%x\n", pInt + 1);
double *pDouble = NULL;
double arr_double[2] = {1.1, 2.2};
pDouble = arr_double;
printf("arr_double第一个元素arr_double[0]的地址是: 0X%x\n", pDouble);
printf("arr_double第二个元素arr_double[1]的地址是: 0X%x\n", pDouble + 1);
3。总结
type *pType = NULL;
3.1 自地址:即“自己的地址”
3.2 自身值:即“自身数据值”
3.3 其他地址:即“别人的地址”
3.4 其他值:即“别人的数据值”
type *pTemp = pType + N;
3.5 其他类型:即“别人的类型”
4。练习讲解
4.1 数组元素的数量
示例
pArr = arr;
printf("%d ", *( pArr + index));
int *pTemp = pArr + index;
4.2 指针数组
Instance
4.2.2.1 输出所有字符串
看指针数组定义:
char *arr[3] = {"abc", "def", "ghi"};
看得到的数组的每个元素,其实是这样的:
char *pChar1 = "abc", *pChar2 = "def", *pChar3 = "ghi"; char *arr[3] = {pChar1, pChar2, pChar3};
数组arr的每个元素是实际上是一个“另一种类型”的指针,即“char”。
arr[0]是指向pChar1的指针,那么pChar1的值或地址是多少?必须是字符串“abc”中字符“a”的地址,那么:
printf("%s ", arr[0]);
的意思是:
printf("%s ", pChar1);
使用另一个pChar1值或地址,从字符“a”的地址开始,输出“b”,一一下方的“c”。
pChar2 和 pChar3 也是如此。
4.2.2.2 输出第一个字符串“abc”中的每个字符
代码如下:
char *pArr = arr[0]; printf("%c ", *(pArr + index) );
给arr[0],即pChar1的值到pArr的值,然后pArr两者它自己的值和另一个地址地址字符'a'。
pArr + index 将索引 * sizeof(char) 字节添加到 pArr 的值中,给出临时指针变量 pTemp:
char *pTemp = pArr + index;
此指针 pTemp 的值或其他地址将为一:字符 'a' 的地址, 'b' , 'c',即pTemp的其他值也会依次为字符'a', 'b', 'c',所以pTemp的指针会经过字符串“abc”
4.3 链表
链表是最常用的指针,在插入节点、删除节点等操作时,你会发现自己在写下面的代码: ♽ 是这个吗?太混乱了!下一个指针就是这个,下一个指针,跳啊跳,满脑子都是粥。哈哈,5维指针分析方法已经有了!不过,关于链表,我觉得我们应该另开一篇文章来讨论一下,链表讨论完了,我们再讨论下一个指针。一旦掌握了窍门,链表就比指针更像纸老虎了。
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。