目录
**指针的深度理解
*什么是指针
*有没有指针变量这个概念
*指针和指针变量有什么区别
*为什么要有指针
*指针的内存布局
*指针的解引用
*如何将数值存储到指定的内存地址
**数组的深度理解
*数组的内存布局
*理解&a和&a[0]的区别
*数组名a作为左值和右值的区别
(一)指针的深度理解
[一]指针
(1)什么是指针?
指针就是地址,那么地址是什么呢??地址就是数据,而数据可以被保存在变量空间中。
(2)有没有指针变量这个概念?
答案是有,保存指针(地址)的变量就叫做指针变量
(3)指针和指针变量有什么区别?
int main()
{
int a = 10;
int *p = &a;//p的空间指向a,而p的内容为a的地址
p = 10; //此时p为左值,表示的是p的空间,即p的空间指向10
int *q = p; //此时p为右值,表示的是p的内容
*p = 10; //解引用p所利用的是p的右值,即*p就是a
system("pause");
return 0;
}
结论:指针就是地址,指针变量就是变量,变量内部保存的是指针(地址)
(4)为什么要有指针?
例:好比一栋宿舍楼没有门牌号,小明随机进入其中一个房间,打电话叫张三找他,张三并不知道他在哪个房间,只能每层楼一个一个房间的找过去,非常浪费时间。而指针就相当于门牌号,有利于寻找,提高编码时的效率
[二]指针的内存布局
[三]指针的解引用
int main()
{
int a=20;
int *p=&a;
*p=30;
return 0;
{
*p的完整理解是,取出p中的地址,访问该地址指向的内存单元(空间或内容)(本质上是一种通过指针变量访问的间接寻址方式)
口诀:对指针解引用,就是指针指向的目标,所以*p就是a
[四]如何将数值存储到指定的内存地址
在比较老的编译器中可以通过,这种寻址方式已经不适用,但是有必要知道这种思维方式
int main()
{
int a = 10;//假设a变量的地址是0x12345678,那么访问a变量,还可以直接通过指针方式进行访问
printf("%d\n", *(int*)0x12345678); //本质是一种直接寻址的方式
*(int*)0x12345678 = 100; //本质是一种直接寻址的方式
system("pause");
return 0;
}
(二)数组的深度理解
数组:数组是具有相同数据类型的集合
int main
{
#define N 10
int a[N]={0};
int b[]={0};
int c[10]={0};//数组的下标可以是宏定义的常数,整数,或者空
int n=10;
int d[n]={0};//在C89、C90中这种定义方法是无法通过编译的,而在C99中可以
return 0;
}
[一]数组的内存布局
我们发现,先定义的变量,地址是比较大的,后续依次减小
a,b,c都在main函数中定义,也就是在栈上开辟的临时变量。而a先定义意味着,a先开辟空间,那么a就先入栈,所以a 的地址最高,其他类似。
而为什么a[0]的地址最小,a[9]的地址最大呢?数组有这么多元素,那么肯定是a[0]先开辟空间,a[0]的地址肯定是最大的。但是为什么a[0]的地址最小?这与我们上面所说的是否相违背??
结论:对于C语言中的变量,会先开辟出一块变量所需的内存空间,然后在进行变量中各个子变量的分配
[二]理解&a和&a[0]的区别
&arr[0] 和 &arr虽然地址数字一样大,但是类型意义完全不同。
口诀:对指针+1,本质上是加上其所指向类型的大小(如果发生类型转换后+1则加上转换后转换后的类型的大小),对于二级即以上的指针+1,则为加上4个字节(地址大小)(32位)(64位加上8个字节)
[三]数组名a作为左值和右值的区别
//数组名可以做右值,代表数组首元素的地址
//数组名做右值,本质等价于&arr[0]
#include<stdio.h>
#include <windows.h>
#define N 10
int main()
{
int arr[N] = { 0 };
char *p = arr;
system("pause");
return 0;
}
数组名不可以做左值!
能够充当左值的,必须是有空间且可被修改的,arr不可以整体使用,只能按照元素为单位进行使用
#include<stdio.h>
#include <windows.h>
#define N 10
int main()
{
int arr[N] = { 0 };
arr = { 1, 2, 3, 4, 5 };//编译器报错
system("pause");
return 0;
}
总结: 这是第一部分的内容。