内存地址
CPU由三个部分组成
算数逻辑单元:对数据执行逻辑运算
控制单元:协调机器活动电路
寄存器组:用于临时储存数据
然而,寄存器能寄存的数据量是很小的
因此,需要内存配合cpu操作
将两个数据相加的操作:
先从内存取一个加数到寄存器中
再从内存取另一个加数到另一个寄存器中
激活算术逻辑单元的加法电路
输出到寄存器
再存放到内存中
如何表达一个数据类型?(以int为例)
列举首地址及占用储存空间大小
指针
取地址运算符&
&数据对象
获取数据对象的首地址和所需存储空间大小
int n;
int * pn = &n; //声明了一个指针变量,用于保存变量n首地址和所需空间大小
char c;
char * pc = &c; //声明了一个指针变量,保存变量c的首地址和所需空间大小我们把pn称作n的指针或者说pn指向n
声明指针类型变量
目标数据类型 * 变量名
指针类型的值是目标数据对象的首地址
#include <stdio.h>
int main()
{
int n1;
int *pn1 = &n1;
printf("%u",pn1);
}输出: 6291044
char类型指针通过char类型来记录所占用的字节大小为一个字节
int类型指针通过int类型来记录所占用的字节大小为四个字节
总结:指针类型是通过值来保存目标数据对象的首地址,通过类型本身来标记目标数据对象的空间大小.
使用指针
取值运算符*
*指针
根据指针中存储的首地址和空间大小找到目标数据对象
#include <stdio.h>
int main()
{
int n = 123;
int *pn = &n;
printf("%u\n",pn);
printf("%d\n",*pn);
return 0;
}输出;
6291044
123
第一个printf打印的是n的首地址
第二个printf打印的是n的值
通过指针修改所指向的数据对象
#include <stdio.h>
int main()
{
int n = 123;
int *pn = &n;
char c = 'C';
char *pc = &c;
*pn = 123;
*pc = 'A';
printf("%d\n",n);
printf("%c\n",c);
printf("%d\n",*pn);
printf("%c\n",*pc);
return 0;
}输出:
123
A
123
A
说明通过指针更改的数据生效
指针类型占用的空间大小
32位 4字节
64为 8字节
指针运算
指针类型与整型加减
指针类型+1后
将首地址向后移动了sizeof(目标数据对象)个字节
指针类型相减后,结果为两个首地址差值除以步长
指针与数组
数组元素在内存中是连续的
第一个元素的首地址就是整个数组的首地址
直接指针指向数组打印出来的地址也是首地址
#include <stdio.h>
int main()
{
int arr[5] = {111,222,333,444,555};
int *p = &arr[0];
printf("%d\n",*p);
printf("%d\n",*(p+1)); //取值运算符的优先级高于算数运算符,所以要把p+1括起来
printf("%d\n",*(p+2));
printf("%d\n",*(p+3));
printf("%d\n",*(p+4));
printf("%d\n",p);
printf("%u\n",arr); //直接打印数组名arr的值也是首地址
int *p2 = arr; //arr在表达式中会被转化为指向数组第一个元素的指针
return 0;
}现在,我们学会了两种访问数组元素的办法
数组名[下标]
*(数组名+偏移量)
例如,我们要访问arr数组的第二个元素
arr[1]和*(arr+1)是完全等价的
[]被称为下标运算符,优先级高于一切运算符
A[k]表达式运算时,会将[]展开为*(A+k)
指针作为参数传递
#include <stdio.h>
void swap(int *x,int *y)
{
int temp = *x;
*x = *y;
*y = temp;
}
int main()
{
int a,b;
a = 1;
b = 2;
printf("%d,%d\n",a,b);
swap(&a,&b);
printf("%d,%d\n",a,b);
return 0;
}void类型指针
只需要传入指针首地址,不需要存储空间大小
#include <stdio.h>
void swap(void *x,void *y,int size)
{
char *px = (char *)x;
char *py = (char *)y;
char temp[128];
for (int i = 0 ;i < size ; i++)
{
temp[i] = px[i];
px[i] = py[i];
py[i] = temp[i];
}
}
int main()
{
int a,b;
a = 1;
b = 2;
printf("%d,%d\n",a,b);
swap(&a,&b,4);
printf("%d,%d\n",a,b);
return 0;
}在这个程序中
因为void只能传入首地址,不能用来取值
所以我们强制转换为char类型(1个字节)
并使用for循环遍历数组(数组内存地址是连续排布的)(int类型有4个字节)
多级指针与指针数组
#include <stdio.h>
int main()
{
int n = 123;
int *pn = &n;
printf("%d\n",pn);
printf("%d\n",&pn);
//指针类型声明中,int * p之间对空格不严格 int*p
int **pnn = &pn;
printf("%d\n",pnn);
printf("%d\n",*pnn);
printf("%d\n",**pnn);
//指针数组
int arr1[5] = {1,2,3,4,5};
int arr2[5] = {6,7,8,9,10};
int arr3[5] = {11,12,13,14,15};
int *pToArr[3] = {arr1,arr2,arr3};
pToArr[0] = arr1;
pToArr[1] = arr2;
pToArr[2] = arr3;
for(int i = 0; i < 3; i++)
{
for(int j = 0; j < 5; j++)
{
printf("%d ",pToArr[i][j]);
}
printf("\n");
}
return 0;
}#include <stdio.h>
int * func()
{
static int n = 123; //static关键字修饰的变量在函数结束后不会被回收
return &n;//函数结束后,函数内部的变量会被回收,如果不想被回收,需要加入关键词function static
}
int main()
{
int *p = func();
printf("%d\n",*p);
return 0;
}#include <stdio.h>
void func(int **p1,int **p2)
{
static int n1 = 123;
static int n2 = 456;
*p1 = &n1;
*p2 = &n2;
}
int main()
{
//NULL是一个宏定义,表示空指针常量
int *a = NULL;
int *b = NULL;
func(&a,&b);
if (a != NULL && b != NULL)
{
printf("%d,%d\n",*a,*b);
}
else
{
printf("指针为空\n");
}
return 0;
}
评论交流
欢迎留下你的想法