C语言指针数组和数组指针
- 格式:doc
- 大小:121.00 KB
- 文档页数:5
指针数组和数组指针释放指针数组和数组指针是C语言中常见的概念,它们在内存管理和数据访问方面起着重要作用。
本文将从人类视角出发,以真实的叙述方式介绍指针数组和数组指针的释放。
在C语言中,指针数组和数组指针都是指针的应用形式,它们与普通的数组有所不同。
指针数组是一个数组,其元素是指针类型;而数组指针是一个指针,指向一个数组。
两者在释放内存时需要注意不同的操作。
我们来看指针数组的释放。
假设我们有一个指针数组ptrArray,其中包含了若干个指针。
在释放内存之前,我们需要逐个释放数组中的指针指向的内存块。
可以通过循环遍历数组的方式,依次释放每个指针指向的内存。
释放完毕后,再使用free函数释放指针数组本身所占用的内存。
这样,我们就完成了指针数组的释放过程。
接下来,我们来看数组指针的释放。
假设我们有一个数组指针pArray,指向一个数组。
在释放内存之前,我们只需使用一次free 函数即可释放整个数组所占用的内存。
因为数组指针指向的是一个连续的内存块,只需释放一次即可。
需要注意的是,在释放指针数组和数组指针时,应确保内存的正确释放顺序。
先释放指针数组中的指针,再释放指针数组本身;先释放数组指针指向的内存,再释放数组指针本身。
这样可以避免内存泄漏和悬空指针的问题。
总结一下,指针数组和数组指针的释放方法是不同的。
对于指针数组,需要逐个释放数组中的指针,并最后释放指针数组本身;对于数组指针,只需一次释放即可。
在释放内存时,需要注意释放的顺序,以确保内存的正确释放。
通过以上的叙述,希望读者能够更好地理解指针数组和数组指针的释放方法,并能够正确地应用于实际的程序开发中。
同时也希望读者能够通过本文的描述,感受到指针数组和数组指针的重要性,以及在内存管理中的作用。
让我们一起努力,深入理解指针数组和数组指针,提升自己在C语言中的编程能力。
理解C语⾔(⼀)数组、函数与指针1 指针⼀般地,计算机内存的每个位置都由⼀个地址标识,在C语⾔中我们⽤指针表⽰内存地址。
指针变量的值实际上就是内存地址,⽽指针变量所指向的内容则是该内存地址存储的内容,这是通过解引⽤指针获得。
声明⼀个指针变量并不会⾃动分配任何内存。
在对指针进⾏间接访问前,指针必须初始化: 要么指向它现有的内存,要么给它分配动态内存。
对未初始化的指针变量执⾏解引⽤操作是⾮法的,⽽且这种错误常常难以检测,其结果往往是⼀个不相关的值被修改,并且这种错误很难调试,因⽽我们需要明确强调: 未初始化的指针是⽆效的,直到该指针赋值后,才可使⽤它。
int *a;*a=12; //只是声明了变量a,但从未对它初始化,因⽽我们没办法预测值12将存储在什么地⽅int *d=0; //这是可以的,0可以视作为零值int b=12;int *c=&b;另外C标准定义了NULL指针,它作为⼀个特殊的指针常量,表⽰不指向任何位置,因⽽对⼀个NULL指针进⾏解引⽤操作同样也是⾮法的。
因⽽在对指针进⾏解引⽤操作的所有情形前,如常规赋值、指针作为函数的参数,⾸先必须检查指针的合法性- ⾮NULL指针。
解引⽤NULL指针操作的后果因编译器⽽异,两个常见的后果分别是返回置0的值及终⽌程序。
总结下来,不论你的机器对解引⽤NULL指针这种⾏为作何反应,对所有的指针变量进⾏显式的初始化是种好做法。
如果知道指针被初始化为什么地址,就该把它初始化为该地址,否则初始化为NULL在所有指针解引⽤操作前都要对其进⾏合法性检查,判断是否为NULL指针,这是⼀种良好安全的编程风格1.1 指针运算基础在指针值上可以进⾏有限的算术运算和关系运算。
合法的运算具体包括以下⼏种: 指针与整数的加减(包括指针的⾃增和⾃减)、同类型指针间的⽐较、同类型的指针相减。
例如⼀个指针加上或减去⼀个整型值,⽐较两指针是否相等或不相等,但是这两种运算只有作⽤于同⼀个数组中才可以预测。
C语言中的数组和指针赋值引言在C语言中,数组和指针是常用的数据类型,并且在许多情况下需要使用赋值操作来初始化数组或为数组元素赋值。
本文将全面介绍C语言中数组和指针的赋值操作,并详细解释它们之间的关系。
数组赋值数组是一种存储相同数据类型元素的集合,并且在内存中是连续分布的。
在C语言中,可以使用以下方式来声明和初始化一个数组:// 声明一个包含5个整数的数组int arr[5];// 初始化数组的元素arr[0] = 10;arr[1] = 20;arr[2] = 30;arr[3] = 40;arr[4] = 50;上述代码中,我们首先声明了一个包含5个整数的数组arr,然后通过arr[index]的方式为数组的每个元素赋值。
需要注意的是,数组的索引从0开始,因此数组的第一个元素的索引是0,第二个元素的索引是1,以此类推。
除了逐个赋值的方式,C语言还提供了一种便捷的初始化数组的方法,即使用花括号({})将元素的值括起来,多个元素之间用逗号分隔。
下面是使用这种方式初始化数组的示例:int arr[5] = {10, 20, 30, 40, 50};此时,数组arr的元素会按照花括号中的顺序被赋予对应的值。
如果数组的大小小于花括号中的元素个数,剩余元素将被自动赋值为0。
如果数组的大小大于花括号中的元素个数,将初始化数组的前面几个元素,其他元素保持默认值(0)。
我们还可以通过循环来赋值数组的元素,特别是在数组非常大的情况下。
下面是使用循环赋值数组元素的示例:int arr[100];int i;for (i = 0; i < 100; i++) {arr[i] = i;}在上述代码中,我们声明了一个包含100个整数的数组arr,然后使用循环为数组的每个元素赋值。
循环变量i的值从0递增到99,依次为数组的索引。
指针赋值指针是一种特殊的数据类型,用于存储内存地址。
在C语言中,可以使用指针来访问和修改内存中的数据。
C语言数组名及指向数组指针的小结C语言的数组名和对数组名取地址转自: /zdcsky123/article/details/6517811相信不少的C语言初学者都知道,数组名相当于指针,指向数组的首地址,而函数名相当于函数指针,指向函数的入口地址。
现在有这样一个问题,如果对数组名取地址,那得到的会是什么呢?很多人立刻会想到:给指针取地址,就是指针的指针,即二级指针嘛!当然这样的结论是错误的,不然这篇笔记也就没有意义了。
下面我们来逐步分析,下面是一段验证这个问题的代码Code:1.#include<stdio.h>2.int main()3.{4.int a[10];5.6.printf("a:/t%p/n", a);7.printf("&a:/t%p/n", &a);8.printf("a+1:/t%p/n", a+1);9.printf("&a+1:/t%p/n", &a+1);10.11.return 0;12.}大家可以编译运行一下,我的输出的结果是:Code:1./*2.a: 0012FF203.&a: 0012FF204.a+1: 0012FF245.&a+1: 0012FF486.*/a和&a指向的是同一块地址,但他们+1后的效果不同,a+1是一个元素的内存大小(增加4),而&a+1增加的是整个数组的内存大小(增加40)。
既a和&a的指向和&a[0]是相同的,但性质不同!读到这里,有很多朋友已经明白其中的机制了,如果还是有些模糊,请继续往下看Code:1.int main()2.{3.int a[10];4.printf("%d/n",sizeof(a));5.return 0;6.}这段代码会输出整个数组的内存大小,而不是首元素的大小,由此我们是否联系到,sizeof(a)这里的a和&a有些相同之处呢?!是的,没错,&a取都得是整个数组的地址!既数组名取地址等价于对数组取地址。
c语言中指针的类型在C语言中,指针是一种非常重要的概念。
它是一个变量,其值为内存地址。
通过使用指针,我们可以直接访问和修改内存中的数据,这使得我们能够更高效地处理数据和实现复杂的数据结构。
在C语言中,指针的类型决定了指针变量可以指向的数据类型。
以下是一些常见的指针类型:1. void指针:void指针是一个通用的指针类型,可以指向任意类型的数据。
它的定义方式为void *ptr。
由于void指针没有具体的数据类型信息,因此在使用时需要进行强制类型转换。
2.整型指针:整型指针可以指向整型数据。
例如,int *ptr可以指向一个int类型的变量。
可以使用指针来操作该变量的地址,读取或修改其值。
3.浮点型指针:浮点型指针可以指向浮点型数据。
例如,float*ptr可以指向一个float类型的变量。
使用指针可以更高效地进行浮点计算,同时可以实现对浮点数据的修改。
4.字符型指针:字符型指针可以指向字符型数据。
例如,char*ptr可以指向一个字符型变量或字符数组。
通过指针,我们可以更方便地操作字符串,包括拷贝、连接、查找等。
5.结构体指针:结构体指针可以指向结构体类型的数据。
结构体是一种自定义的数据类型,可以包含多个不同数据类型的成员变量。
通过结构体指针,我们可以访问和修改结构体的成员,实现对结构体的操作。
6.数组指针:数组指针可以指向数组类型的数据。
例如,int*ptr可以指向一个int类型的数组。
通过指针,我们可以遍历数组中的每个元素,进行读取、修改或其他操作。
7.函数指针:函数指针可以指向函数。
函数是一段可执行的代码块,通过函数指针,我们可以像调用普通函数一样调用被指向的函数。
8.指向指针的指针:指向指针的指针是指针的指针,通过它可以实现更复杂的数据结构,如链表、二维数组等。
在C语言中,指针的类型非常灵活,可以根据实际需求选择合适的指针类型。
通过使用指针,我们可以提高程序的效率和灵活性,同时能够更方便地进行内存管理和数据操作。
C语言指针用法详解C语言指针用法详解指针可以说是集C语言精华之所在,一个C语言达人怎么可以不会指针呢。
下面店铺给大家介绍C语言指针用法,欢迎阅读!C语言指针用法详解(1)关于指针与数组的存储a、指针和数组在内存中的存储形式数组p[N]创建时,对应着内存中一个数组空间的分配,其地址和容量在数组生命周期内一般不可改变。
数组名p本身是一个常量,即分配数组空间的地址值,这个值在编译时会替换成一个常数,在运行时没有任何内存空间来存储这个值,它和数组长度一起存在于代码中(应该是符号表中),在链接时已经制定好了;而指针*p创建时,对应内存中这个指针变量的空间分配,至于这个空间内填什么值即这个指针变量的值是多少,要看它在程序中被如何初始化,这也决定了指针指向哪一块内存地址。
b、指针和数组的赋值与初始化根据上文,一般情况下,数组的地址不能修改,内容可以修改;而指针的内容可以修改,指针指向的内容也可以修改,但这之前要为指针初始化。
如:int p[5];p=p+1; 是不允许的而p[0]=1; 是可以的;//int *p;p=p+1; 是允许的p[0]=1; 是不允许的,因为指针没有初始化;//int i;int *p=&i;p[0]=1; 是允许的;对于字符指针还有比较特殊的情况。
如:char * p="abc";p[0]='d'; 是不允许的为什么初始化了的字符指针不能改变其指向的内容呢?这是因为p 指向的是“常量”字符串,字符串"abc"实际是存储在程序的静态存储区的,因此内容不能改变。
这里常量字符串的地址确定在先,将指针指向其在后。
而char p[]="abc";p[0]='d'; 是允许的这是因为,这个初始化实际上是把常量直接赋值给数组,即写到为数组分配的内存空间。
这里数组内存分配在先,赋值在后。
(2)关于一些表达式的含义char *p, **p, ***p;char p[],p[][],p[][][];char *p[],*p[][],**p[],**p[][],*(*p)[],(**p)[],(**p)[][];能清晰地知道以上表达式的含义吗?(知道的去死!)第一组:char *p, **p, ***p;分别为char指针;char*指针,即指向char*类型数据地址的指针;char**指针,即指向char**类型数据的指针;他们都是占4字节空间的指针。
指针数组和数组指针详解指针数组和数组指针1.定义int *p[4]; //泄义了一个指针数组p, p—共有4个单元,每个单元都是一个int型的指针int (*p)[4]; //适义了一个数组指针p, p可以指向一个拥有4个单元的int型数组2.指针数组的用法★includeint mainO{int *p[4];int a二1, b二2, c二3, d=4;p[0] = &a;p[l] = &b;p[2] = &c;p[3] = &d;printf C%d %d %d %d\n\ *p[0], *p[l], *p[2], *(p[3]));return 0;}程序输岀:12 3 4分析:指针数组的用法比较简单,注意一点*讥0]和*(讥0])是一样的,因为在C语言中口的优先级要高于*运算符。
3.数组指针的用法数组指针的用法比较复杂,理解相对来说也比较困难,还是需要结合一些实际的例子来一步步的理解。
例子1:int mainO{int a 18] = {1, 2, 3, 4, 5, 6, 7, 8};int *p = a;printf(”%d\n", p[2]);return 0;}程序输岀结果:3分析1:这是平时在写程序时经常用到的一种写法,但是却隐藏着一些知识点可能平时都没有太注意到。
这里P是一个int型的指针,然而在程序中却将p类似于数组来使用,这个怎么理解呢?其实这样写的话,就相当于将P作为基址[2]表示的是相对于基址的偏移,这里是偏移两个P指向类型的单元,也就是得到的a的第三个单元(单元从1开始汁数)的值也就是3。
同时记住:a的理解有两种:第一种a表示这8个int单元的总称,体现在&a的时候,这个时候&a 的类型为int (*) [8];第二种理解a的值代表的是一个int类型的指针,体现在a[l]=*(a+1)这种操作中。
例子2★includeint mainO{int a [8] = {1, 2, 3, 4, 5, 6, 7, 8};int (*p)[8] = &a;printf("%p %p ", p, a); 〃这里是用的a的值,所以a体现的是指针的性质printf (?,%d "、((*p) [3]));printf ("%d\n", *p[3]);return 0;}程序输出:0012FF60 0012FF60 4 1245120分析2:可以看到p和a的值输出是一样的,但是要记住这里的p和a的类型可是完全不一样的,所以在赋值的时候没有直接将a赋值给p而是用了&a。
C语⾔指针知识点总结1.指针的使⽤和本质分析(1)初学指针使⽤注意事项1)指针⼀定要初始化,否则容易产⽣野指针(后⾯会详细说明);2)指针只保存同类型变量的地址,不同类型指针也不要相互赋值;3)只有当两个指针指向同⼀个数组中的元素时,才能进⾏指针间的运算和⽐较操作;4)指针只能进⾏减法运算,结果为同⼀个数组中所指元素的下表差值。
(2)指针的本质分析①指针是变量,指针*的意义:1)在声明时,*号表⽰所声明的变量为指针。
例如:int n = 1; int* p = &n;这⾥,变量p保存着n的地址,即p<—>&n,*p<—>n2)在使⽤时,*号表⽰取指针所指向变量的地址值。
例如:int m = *p;②如果⼀个函数需要改变实参的值,则需要使⽤指针作为函数参数(传址调⽤),如果函数的参数数据类型很复杂,可使⽤指针代替。
最常见的就是交换变量函数void swap(int* a, int* b)③指针运算符*和操作运算符的优先级相同例如:int m = *p++;等价于:int m= *p; p++;2.指针和数组(1)指针、数组、数组名如果存在⼀个数组 int m[3] = {1,2,3};定义指针变量p,int *p = m(这⾥m的类型为int*,&a[0]==>int*)这⾥,其中,&m为数组的地址,m为数组0元素的地址,两者相等,但意义不同,例如:m+1 = (unsigned int)m + sizeof(*m)&m+1= (unsigned int)(&m) + sizeof(*&m)= (unsigned int)(&m) + sizeof(m)m+1表⽰数组的第1号元素,&m+1指向数组a的下⼀个地址,即数组元素“3”之后的地址。
等价操作:m[i]←→*(m+i)←→*(i+m)←→i[m]←→*(p+i)←→p[i]实例测试如下:1 #include<stdio.h>23int main()4 {5int m[3] = { 1,2,3 };6int *p = m;78 printf(" &m = %p\n", &m);9 printf(" m = %p\n", m);10 printf("\n");1112 printf(" m+1 = %p\n", m + 1);13 printf(" &m[2] = %p\n", &m[2]);14 printf(" &m+1 = %p\n", &m + 1);15 printf("\n");1617 printf(" m[1] = %d\n", m[1]);18 printf(" *(m+1) = %d\n", *(m + 1));19 printf(" *(1+m) = %d\n", *(1 + m));20 printf(" 1[m] = %d\n", 1[m]);21 printf(" *(p+1) = %d\n", *(p + 1));22 printf(" p[1] = %d\n", p[1]);2324return0;25 }输出结果为:(2)数组名注意事项1)数组名跟数组长度⽆关;2)数组名可以看作⼀个常量指针;所以表达式中数组名只能作为右值使⽤;3)在以下情况数组名不能看作常量指针:- 数组名作为sizeof操作符的参数- 数组名作为&运算符的参数(3)指针和⼆维数组⼀维数组的指针类型是 Type*,⼆维数组的类型的指针类型是Type*[n](4)数组指针和指针数组①数组指针1)数组指针是⼀个指针,⽤于指向⼀个对应类型的数组;2)数组指针的定义⽅式如下所⽰:int (*p)[3] = &m;②指针数组1)指针数组是⼀个数组,该数组⾥每⼀个元素为⼀个指针;2)指针数组的定义⽅式如下所⽰:int* p[5];3.指针和函数(1)函数指针函数的本质是⼀段内存中的代码,函数的类型有返回类型和参数列表,函数名就是函数代码的起始地址(函数⼊⼝地址),通过函数名调⽤函数,本质为指定具体地址的跳转执⾏,因此,可定义指针,保存函数⼊⼝地址,如下所⽰:int funcname(int a, int b);int(*p)(int a, int b) = funcname;上式中,函数指针p只能指向类型为int(int,int)的函数(2)函数指针参数对于函数int funcname(int a, int b);普通函数调⽤ int funcname(int, int),只能调⽤函数int func(int, int)函数指针调⽤ intname(*func)(int,int),可以调⽤任意int(int,int)类型的函数,从⽽利⽤相同代码实现不同功能,实例测试如下,假设有两个相同类型的函数func1和func2:1int func1(int a, int b, int c)2 {3return a + b + c;4 }56int func2(int a, int b, int c)7 {8return a - b - c;9 }普通函数调⽤和函数指针调⽤⽅式及结果如下所⽰1 printf("普通函数调⽤\n");2 printf("func1 = %d\n", func1(100, 10, 1));3 printf("func2 = %d\n", func2(100, 10, 1));4 printf("\n");56 printf("函数指针调⽤\n");7int(*p)(int, int, int) = NULL;8 p = func1;9 printf("p = %d\n", p(100, 10, 1));10 p = func2;11 printf("p = %d\n", p(100, 10, 1));12 printf("\n");需要注意的是,数组作为函数参数的时候,会变为函数指针参数,即:int funcname( int m[] )<——>int funcname ( int* m );调⽤函数时,传递的是数组名,即funcname(m);(3)回调函数利⽤函数指针,可以实现⼀种特殊的调⽤机制——回调函数。
C语言指针数组和数组指针
一、指针数组和数组指针的内存布局
初学者总是分不出指针数组与数组指针的区别。
其实很好理解:
指针数组:首先它是一个数组,数组的元素都是指针,数组占多少个字节由数组本身决定。
它是“储存指针的数组”的简称。
数组指针:首先它是一个指针,它指向一个数组。
在32 位系统下永远是占4 个字节,至于它指向的数组占多少字节,不知道。
它是“指向数组的指针”的简称。
下面到底哪个是数组指针,哪个是指针数组呢:
A)
int *p1[10];
B)
int (*p2)[10];
每次上课问这个问题,总有弄不清楚的。
这里需要明白一个符号之间的优先级问题。
“[]”的优先级比“*”要高。
p1 先与“[]”结合,构成一个数组的定义,数组名为p1,int *修饰的是数组的内容,即数组的每个元素。
那现在我们清楚,这是一个数组,其包含10 个指向int 类型数据的指针,即指针数组。
至于p2 就更好理解了,在这里“()”的优先级比“[]”高,“*”号和p2 构成一个指针的定义,指针变量名为p2,int 修饰的是数组的内容,即数组的每个元素。
数组在这里并没有名字,是个匿名数组。
那现在我们清楚p2 是一个指针,它指向一个包含10 个int 类型数据的数组,即数组指针。
我们可以借助下面的图加深理解:
二、int (*)[10] p2-----也许应该这么定义数组指针
这里有个有意思的话题值得探讨一下:平时我们定义指针不都是在数据类型后面加上指针变量名么?这个指针p2 的定义怎么不是按照这个语法来定义的呢?也许我们应该这样来定义p2:
int (*)[10] p2;
int (*)[10]是指针类型,p2 是指针变量。
这样看起来的确不错,不过就是样子有些别扭。
其实数组指针的原型确实就是这样子的,只不过为了方便与好看把指针变量p2 前移了而已。
你私下完全可以这么理解这点。
虽然编译器不这么想。
^_^
三、再论a 和&a 之间的区别
既然这样,那问题就来了。
前面我们讲过a 和&a 之间的区别,现在再来看看下面的代码:
int main()
{
char a[5]={'A','B','C','D'};
char (*p3)[5] = &a;
char (*p4)[5] = a;
return 0;
}
上面对p3 和p4 的使用,哪个正确呢?p3+1 的值会是什么?p4+1 的值又会是什么?毫无疑问,p3 和p4 都是数组指针,指向的是整个数组。
&a 是整个数组的首地址,a是数组首元素的首地址,其值相同但意义不同。
在C 语言里,赋值符号“=”号两边的数据类型必须是相同的,如果不同需要显示或隐式的类型转换。
p3 这个定义的“=”号两边的数据类型完全一致,而p4 这个定义的“=”号两边的数据类型就不一致了。
左边的类型是指向整个数组的指针,右边的数据类型是指向单个字符的指针。
在Visual C++6.0 上给出如下警告:
warning C4047: 'initializing' : 'char (*)[5]' differs in levels of indirection from 'char *'。
还好,这里虽然给出了警告,但由于&a 和a 的值一样,而变量作为右值时编译器只是取变量的值,所以运行并没有什么问题。
不过我仍然警告你别这么用。
既然现在清楚了p3 和p4 都是指向整个数组的,那p3+1 和p4+1 的值就很好理解了。
但是如果修改一下代码,会有什么问题?p3+1 和p4+1 的值又是多少呢?
int main()
{
char a[5]={'A','B','C','D'};
char (*p3)[3] = &a;
char (*p4)[3] = a;
return 0;
}
甚至还可以把代码再修改:
int main()
{
char a[5]={'A','B','C','D'};
char (*p3)[10] = &a;
char (*p4)[10] = a;
return 0;
}
这个时候又会有什么样的问题?p3+1 和p4+1 的值又是多少?
上述几个问题,希望读者能仔细考虑考虑。
四、地址的强制转换
先看下面这个例子:
struct Test
{
int Num;
char *pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
假设p 的值为0x100000。
如下表表达式的值分别为多少?
p + 0x1 = 0x___ ?
(unsigned long)p + 0x1 = 0x___?
(unsigned int*)p + 0x1 = 0x___?
我相信会有很多人一开始没看明白这个问题是什么意思。
其实我们再仔细看看,这个知识点似曾相识。
一个指针变量与一个整数相加减,到底该怎么解析呢?
还记得前面我们的表达式“a+1”与“&a+1”之间的区别吗?其实这里也一样。
指针变量与一个整数相加减并不是用指针变量里的地址直接加减这个整数。
这个整数的单位不是byte 而是元素的个数。
所以:p + 0x1 的值为0x100000+sizof (Test)*0x1。
至于此结构体的大小为20byte,前面的章节已经详细讲解过。
所以p +0x1 的值为:0x100014。
(unsigned long)p + 0x1 的值呢?这里涉及到强制转换,将指针变量p 保存的值强制转换成无符号的长整型数。
任何数值一旦被强制转换,其类型就改变了。
所以这个表达式其实就是一个无符号的长整型数加上另一个整数。
所以其值为:0x100001。
(unsigned int*)p + 0x1 的值呢?这里的p 被强制转换成一个指向无符号整型的指针。
所以其值为:0x100000+sizof(unsigned int)*0x1,等于0x100004。
上面这个问题似乎还没啥技术含量,下面就来个有技术含量的:在x86 系统下,其值为多少?
intmain()
{
int a[4]={1,2,3,4};
int *ptr1=(int *)(&a+1);
int *ptr2=(int *)((int)a+1);
printf("%x,%x",ptr1[-1],*ptr2);
return 0;
}
这是我讲课时一个学生问我的题,他在网上看到的,据说难倒了n 个人。
我看题之后告诉他,这些人肯定不懂汇编,一个懂汇编的人,这种题实在是小case。
下面就来分析分析这个问题:
根据上面的讲解,&a+1 与a+1 的区别已经清楚。
ptr1:将&a+1 的值强制转换成int*类型,赋值给int* 类型的变量ptr,ptr1 肯
定指到数组a 的下一个int 类型数据了。
ptr1[-1]被解析成*(ptr1-1),即ptr1 往后退4 个byte。
所以其值为0x4。
ptr2:按照上面的讲解,(int)a+1 的值是元素a[0]的第二个字节的地址。
然后把这个地址强制转换成int*类型的值赋给ptr2,也就是说*ptr2 的值应该为元素a[0]的第二个字节开始的连续4 个byte 的内容。
其内存布局如下图:
好,问题就来了,这连续4 个byte 里到底存了什么东西呢?也就是说元素
a[0],a[1]里面的值到底怎么存储的。
这就涉及到系统的大小端模式了,如果懂汇编的话,这根本就不是问题。
既然不知道当前系统是什么模式,那就得想办法测试。
大小端模式与测试的方法在第一章讲解union 关键字时已经详细讨论过了,请翻到彼处参看,这里就不再详述。
我们可以用下面这个函数来测试当前系统的模式。
int checkSystem( )
{
union check
{
int i;
char ch;
} c;
c.i = 1;
return (c.ch ==1);
}
如果当前系统为大端模式这个函数返回0;如果为小端模式,函数返回1。
也就是说如果此函数的返回值为1 的话,*ptr2 的值为0x2000000。
如果此函数的返回值为0 的话,*ptr2 的值为0x100。