C语言基础学习之指针,数组和内存杂讲
c语言基础学习之指针,数组和内存杂讲
大端与小端 sizeof对数组名和普通指针的区别 下标运算符 数组指针和指针数组
c语言允许直接访问物理地址,可以直接对硬件进行操作
因此c既具有高级语言的功能,又具有低级语言的许多功能,能够像汇编语言一样对位、字节和地址进行操作。
我们每个知识点会用具体的例子实现,方便理解。·
1.大端与小端
执行下面的代码,看看输出结果是什么(注意:源文件后缀为.c)
#include int main(){ short num = 0x1122; //short 占两个字节 char *c; //char 占一个字节 c = # if(*c == 0x22) printf("this is little end\n"); else printf("this is big end\n"); return 0; }
这表示我们的计算机处于小端模式,那么什么是大端模式和小端模式呢?
大端:数据的低位保存在高地址中,而高位保存在低地址中。 小端: 数据的低位保存在低地址中,高位保存在高地址中。
从上述的例子中,我们先定义一个short型的变量,我们知道short类型占两个字节,把0x1122赋给这个变量,再定义一个指向字符型的指针变量,把short变量的地址赋给它,最终输出显示 这个字符型指针指向的就是short型变量的低位。我们可以用下图来表示这个过程。
0x1122 11是高位,22是低位,我们让short的地址赋给c,其实就是让c指向short的位置,但因为char类型只有一个字节,所以只会输出short类型中的一个字节,如图所示:
*c输出结果为22,代表目前低位存在低地址中。所以现在机器是小端模式。
2.sizeof的注意项
#include int main(){ int a[3] = {1,2,3}; int *p = a; printf("%d\n", sizeof(a)); printf("%d\n", sizeof(p)); return 0; }
输出结果是这样
因为a是数组名,sizeof在这里会自动判断,于是输出这个数组的大小。但虽然指针变量p也指向数组首地址,但sizeof判断接收到的是指针变量而不是数组名时,会输出 当前指针类型的大小。这个数组有三个整形变量,每个变量占四个字节,所以就是大小就是12字节,在64位下,指针变量的大小是8字节(32位下是4字节)。
3.下标运算符
在学完数组之后,我们都知道[]是放数组下标的地方,但怎么用其他方式表示呢?实际上,a[n] 就等同于 * (a+n)。同样我们可以这样写,n[a],这样写好像是错误但,但实际上它表示 *(n+(a)),其实和上面表示的意思是相同的。
下面是个例子
#include int main(int argc, char *argv[]){ int nums[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; printf("%d\n", nums[1][-2]); printf("%d\n", (-1)[nums][5]); printf("%d\n", -1[nums][5]); return 0; }nums[1][-2] 表示 : ((nums+1)+(-2)) 其实就是 nums[0][1] 结果是 2。 (-1)[nums][5] 表示:(*(nums+(-1))+5) 先向前移动一个一维元素大小(数组),再向后移动五个二维元素的大小(整形变量),其实就是nums[0][3],结果是3。 -1[nums][5] 表示:-((1+(nums))+5),其实就是-a[2][2],结果是-9。
4.数组指针和指针数组
我们先来看两行代码:int * a[5]和 int (* a)[5],它们的意义相同吗?答案是否定的。int *a[5] 表示a是一个数组,里面每个数组元素都是指向整形的指针变量。int ( *a)[5],()的优先级高于[],所以首先a是一个指针类型,其次这个指针指向一个数组。
下面是个例子:
#include int main(){ int array[5] = {1, 2, 3, 4, 5}; printf("%p %p\n", array, &array[0]); printf("%p %p\n", &array + 1, &array[0] + 1); int (*parray)[5] = &array; //数组指针 for (int i = 0; i < 5; i++) { printf("%d ", *parray[i]); } printf("\n"); int array2[2][5] = { {1, 2, 3, 4, 5}, {6, 7, 8, 9, 10} }; parray = array2; printf("%d %d\n", *(*(array2 + 1) + 1), parray[1][1]); int (*parray2)[2][5] = &array2; for (int i = 0; i < 2; i++) { for (int j = 0; j < 5; j++) { printf("%d ", (*parray2)[i][j]); } printf("\n"); } return 0; }
注:%p代表该变量的地址。
首先输出 array的地址 和array[0]的地址,这表明,数组名就表示数组的首地址。
接下来定义一个数组指针指向array,此时给这个指针每进行一次下标运算符,在内存中移动的是整个数组的大小,所以除了本身,其他运算后的数值都是不可预测的。
后面的也是相同的道理,只不过是二维数组的东西,理解以上之后会很容易理解这些。
上一篇: jsp遍历所有数据标签与转义标签
下一篇: ps怎么设计切开的柠檬图标?