1. 内存
1.1 什么是内存
内存是一种存储器,用来存放数据, 程序,所有的程序都是加载到内存中运行的
1.2 内存结构
内存由两部分组成,存储单元地址,和存储空间组成
每一个存储单元地址,存放1个字节,8个比特位
1.3 内存的大小
有多少个存储单元地址?
地址的个数由机器地址线决定,在32位的机器上,地址为32,地址的个数为 232 = 4,294,967,296
4,294,967,296 个 字节 -----> 4GB
1.4 如何理解内存
内存可以理解为一个房子,通过访问门牌号码,就可以找到相对应的房间
通过访问内存地址单元,就可以取出存储空间中的数据
2. 指针
2.1 什么是指针,指针变量
指针是存储单元地址,也就是地址
指针变量是存放地址的变量
例子:
#include <stdio.h>
int main()
{
int a = 1;
int* pa = &a;
printf("0x%p", pa);
return 0;
}
解析:
#include <stdio.h>
int main()
{
int a = 1;
int* pa = &a;
printf("0x%p", pa);
return 0;
}
int a = 1; 在内存中开辟4个字节,存入1
int* pa = &a; &a取出变量a的地址,存入指针变量pa中
printf("0x%p", pa); 最后,以地址的形式打印指针变量pa的值,也就是变量a的地址
pa在这个例子中就是一个指针变量,pa存储变量a的地址
2.2 如何理解指针和指针变量
指针是地址, 指针变量是存储地址的变量
#include <stdio.h>
int main()
{
int a = 1;
int* pa = &a;
printf("0x%p", pa);
return 0;
}
int *pa = &a;
* 表示pa, 是一个指针变量,存储地址
int 表示, pa 存储的变量a的类型是 int
2.3 &取地址,*间接寻址操作符
&, 表示取出一个变量的起始地址
*, 表示访问内存单元地址
#include <stdio.h>
int main()
{
int a = 10;
int* pa = &a;
*pa = 20;
prinf("%d\n",*pa);
}
&a, 取出变量a的起始地址,存入指针变量pa中
*pa = 20, 此时,pa存储的是变量a的地址, *pa = 20,表示访问a的地址,将存储空间中的值改为20
2.4 指针变量的大小
指针变量存储一个变量的地址,存储地址
在32位地址线机器上,地址为32位,指针变量大小为4个字节
#include <stdio.h>
int main()
{
int a = 0;
int* pa = &a;
printf("%d\n", sizeof(pa));
return 0;
}
3. 指针类型
口语中的指针就是指针变量
3.1 指针类型
char *pc = NULL;
int *pi = NULL;
short *ps = NULL;
long *pl = NULL;
float *pf = NULL;
double *pd = NULL;
指针类型,根据存储变量的类型决定, 强制类型转换除外
3.2 指针类型的意义
指针变量的大小根据机器地址线决定,32位为4个字节, 64位为8个字节
既然指针变量的大小都是固定的,指针类型有什么意义?
1. 指针类型决定 *间接寻址 访问几个字节
#include <stdio.h>
int main()
{
int a = 0x11223344;
int* pa = &a;
*pa = 0;
printf("%d\n", a);
}
#include <stdio.h>
int main()
{
int a = 0x11223344;
char* pa = (char*)&a;
*pa = 0;
printf("%d\n", a);
}
当 pa 为整型指针时,*访问4个字节,*pa = 0, 同时访问4个内存单元地址中的内存空间,然后赋值为0
当 pa 为字符指针时, * 只能访问1个字节, *pa = 0, 只能访问1个地址中的内存空间,所以只能将一个地址赋值为0
2. 指针类型决定 指针的步长
类型决定,指针+1跳过几个字节
整型指针 + 1, 跳过4个字节
字符指针 + 1, 跳过1个字节
#include <stdio.h>
int main()
{
int a = 0;
int* pa = &a;
printf("%p\n", pa);
printf("%p\n", pa + 1);
return 0;
}
#include <stdio.h>
int main()
{
char a = 0;
char* pa = &a;
printf("%p\n", pa);
printf("%p\n", pa + 1);
return 0;
}
4. 指针运算
4.1 指针 +- 整数
#include <stdio.h>
int main()
{
int a = 1;
int* pa = &a;
printf("%p\n", pa);
printf("%p\n", pa + 1);
printf("%p\n", pa - 1);
return 0;
}
整型指针 + 1, 向地址高位移动4个字节
整型指针 - 1, 向地址低位移动4个字节
4.2 指针 - 指针
#include <stdio.h>
int main()
{
int arr[10] = { 0 };
printf("%d\n", &arr[9] - &arr[0]);
return 0;
}
指针 - 指针的值是两个指针之间的元素个数
// 求字符串长度
#include <stdio.h>
int len1(char* str)
{
int count = 0;
char* ps = str;
while (*str != '\0')
{
str++;
}
return str - ps; // 指针 - 指针
}
int main()
{
char arr[] = "abcdef";
int res = len1(arr);
printf("%d\n", res);
return 0;
}
4.3 指针关系运算
#include <stdio.h>
int main()
{
int arr[5] = { 0 };
int count = 1;
for (int* pa = &arr[0]; pa < &arr[5]; pa++)
{
*pa = count;
printf("%d ", *pa);
count++;
}
printf("\n");
}
pa < &arr[5],比较的是地址的高低位
5. 二级指针
5.1 什么是二级指针
#include <stdio.h>
int main()
{
int a = 1;
int* pa = &a; // 一级指针 pa
int** ppa = &pa; // 二级指针 ppa
return 0;
}
二级指针是一个指针变量,存储一级指针变量的地址
5.2 如何理解二级指针
#include <stdio.h>
int main()
{
int a = 1;
int* pa = &a; // 一级指针 pa
int** ppa = &pa; // 二级指针 ppa
return 0;
}
只要是一个变量,都会在内存中开辟一块存储空间
指针也是一个变量,在内存中也会有地址
&pa, 取出一级指针变量pa的地址存储入ppa中
ppa二级指针,存储一级指针pa的地址
int * pa = &a, * 表示pa是一个指针变量, int 表示pa存储a的类型为 int
int * *ppa = &pa, *ppa 表示ppa是个指针变量, int*表示ppa存储的pa的类型是一个一级整型指针int*
5.3 二级指针的使用
#include <stdio.h>
int main()
{
int a = 1;
int* pa = &a; // 一级指针 pa
int** ppa = &pa; // 二级指针 ppa
printf("%d\n", a);
*(*ppa) = 2;
printf("%d\n", a);
return 0;
}
(*ppa), 表示访问ppa的存储空间, 空间内存放的是一级指针pa的地址
*(*ppa) --> 通过pa的地址,访问pa的存储空间, 变量a的地址
(*ppa) = (pa) ----> *(*ppa) = *(pa)
所以,实际上访问的是a的存储空间
*(*ppa) = 2 , 将空间的值改为2
5.4 三级指针
三级指针就是存储二级指针的地址
#include <stdio.h>
int main()
{
int a = 1;
int* pa = &a; // 一级指针 pa
int* *ppa = &pa; // 二级指针 ppa
int** *pppa = &ppa; // 三级指针 pppa
return 0;
}
*pppa,表示pppa是一个指针, int** 表示pppa存储的ppa的类型是二级整型指针
6. 字符指针
6.1 常量字符串的值是什么
#include <stdio.h>
int main()
{
char* str = "abcdef";
printf("%s\n", str);
return 0;
}
常量字符串的值等于首字符的地址,指针变量str, 存储的是字符a的地址
%s, 表示打印\0之前所有的字符
6.2 C/C++ 存储常量字符串的规则
#include <stdio.h>
int main()
{
char str1[] = "hello bit.";
char str2[] = "hello bit.";
const char* str3 = "hello bit.";
const char* str4 = "hello bit.";
if (str1 == str2)
printf("str1 and str2 are same\n");
else
printf("str1 and str2 are not same\n");
if (str3 == str4)
printf("str3 and str4 are same\n");
else
printf("str3 and str4 are not same\n");
return 0;
}
C/C++ 会把常量字符串存储到一个单独的存储区中
当多个指针同时存储相同的常量字符串时,指针存储相同的首字符地址
7. 指针和数组
7.1 区分指针和数组
指针和数组是两个不同的对象
指针是存储地址的变量,数组是一组相同类型元素的集合
#include <stdio.h>
int main()
{
int arr[5] = {0}; // 数组arr
int* pa = arr; // 指针pa
return 0;
}
7.2 数组名 = 数据首元素地址
#include <stdio.h>
int main()
{
int arr[5] = { 0 };
printf("0x%p\n", arr);
printf("0x%p\n", &arr[0]);
return 0;
}
7.3 通过指针访问数组
#include <stdio.h>
int main()
{
int arr[5] = { 1,2,3,4,5 };
int* pa = arr;
for (int i = 0; i < 5; i++)
{
printf("%d ", *(pa + i));
}
printf("\n");
return 0;
}
8. 指针数组
8.1 什么是指针数组
#include <stdio.h>
int main()
{
char* arr[3] = { "aaa","bbb","ccc" }; //字符指针数组
int i = 0;
for (i = 0; i < 3; i++)
{
printf("%s\n", *(arr + i));
}
return 0;
}
#include <stdio.h>
int main()
{
int arr1[5] = { 1,2,3,4,5 };
int arr2[5] = { 2,3,4,5,6 };
int arr3[5] = { 3,4,5,6,7};
int* arr[3] = { arr1, arr2, arr3 };
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
printf("%d ", *(arr[i] + j));
}
printf("\n");
}
}
指针数组是存储地址的数组
9. 数组指针
9.1 &数组名,数组名的区别
#include <stdio.h>
int main()
{
int arr[10] = { 0 };
// arr
printf("%p\n", arr);
printf("%p\n\n", arr + 1);
// &arr
printf("%p\n", &arr);
printf("%p\n", &arr + 1);
}
arr, 是数组首元素的地址
&arr, 是数组的地址
9.2 什么是数组指针
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int (*pa)[10] = &arr; //数组指针
}
数组指针是存储数组地址的指针
9.3 如何理解数组指针
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int (*pa)[10] = &arr; //数组指针
}
(*pa),表示pa是一个指针,
[10], 表示pa存储的数组有10个元素
(*pa)前面的int,表示每一个元素的类型是int
9.4 数组指针的使用
#include <stdio.h>
void print(int (*pa)[5], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf("%d ", (*(pa + i))[j]);
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { {1,2,3,4,5}, {2,3,4,5,6}, {3,4,5,6,7} };
print(arr, 3, 5);
return 0;
}
解析:
二维数组的数组名 = 二维数组第一行的地址
int (*pa)[5],接收第一行地址, 第一行有5个元素,类型是int
( *(pa + i) ) [j]
(pa + i),pa+0,就是第一行的地址,以此类推
( *(pa + i) )[j], 访问第几行的地址,拿到数组元素, 然后用下标j,锁定元素
10. 函数指针
10.1 什么是函数指针
#include <stdio.h>
int sum(int x, int y)
{
return x + y;
}
int main()
{
int (*pf)(int, int) = ∑ // 函数指针
int res = (*pf)(1, 2);
printf("%d\n", res);
return 0;
}
函数指针,存储函数地址的指针
10.2 如何理解函数指针
#include <stdio.h>
int sum(int x, int y)
{
return x + y;
}
int main()
{
int (*pf)(int, int) = ∑
int res = (*pf)(1, 2);
printf("%d\n", res);
return 0;
}
int (*pf) (int, int)
(*pf), * 表示pf是一个指针
(int, int), 表示pf存储的是函数地址,函数有两个参数
int,表示函数的返回类型是int
11. 函数指针数组
11.1 函数指针数组
#include <stdio.h>
int main()
{
int (*pf[3])(int, int); //函数指针数组
return 0;
}
函数指针数组,是存储函数地址的数组
11.2 如何理解函数指针数组
#include <stdio.h>
int main()
{
int (*pf[3])(int, int); //函数指针数组
return 0;
}
( * pf[3] ), []优先级更高, 所以pf, 是一个数组, 数组有3个元素
int (*)(int, int), (*) 表示这是一个指针
(int, int) 表示指针存储的是函数地址, 这个函数有两个int形参,
*前面的 int, 表示 返回类型是int
11.3 函数指针数组的使用
#include <stdio.h>
void menu()
{
printf("**************************************\n");
printf("************ 1.add 2.sub *************\n");
printf("************ 3.mul 4.div *************\n");
printf("************ 0.exit *************\n");
printf("**************************************\n");
}
int add(int x, int y)
{
return x + y;
}
int sub(int x, int y)
{
return x - y;
}
int mul(int x, int y)
{
return x * y;
}
int div(int x, int y)
{
return x / y;
}
int main()
{
int x = 0;
int y = 0;
int n = 0;
int res = 0;
do
{
menu();
printf("输入: ");
scanf("%d", &n);
if (n == 0)
{
break;
}
else if(n > 0 && n < 5)
{
printf("输入两个数: ");
scanf("%d %d", &x, &y);
int (*pf[5])(int, int) = { NULL, &add, &sub,&mul,&div };
res = pf[n](x, y);
printf("%d\n", res);
}
else
{
printf("error\n");
}
} while (n);
}
这里的pf, 就是一个函数指针数组, 数组存放4个函数的地址
12. 存储函数指针数组的指针
12.1 什么是存储函数指针数组的指针
#include <stdio.h>
int main()
{
int(*pf[5])(int, int); // 函数指针数组
int(*(*ppf)[5])(int, int) = &pf; //存储函数指针数组的指针
}
12.1 如何理解
int ( * ( *ppf ) [5] ) (int, int)
( *ppf ),表示ppf是一个指针
[5], 表示ppf存储的是一个数组, 数组有5个元素
int(*)(int, int), 每一个元素的类型是函数指针
13. 回调函数
13.1 什么是回调函数
#include <stdio.h>
void menu()
{
printf("**************************************\n");
printf("************ 1.add 2.sub *************\n");
printf("************ 3.mul 4.div *************\n");
printf("************ 0.exit *************\n");
printf("**************************************\n");
}
int add(int x, int y)
{
return x + y;
}
int sub(int x, int y)
{
return x - y;
}
int mul(int x, int y)
{
return x * y;
}
int div(int x, int y)
{
return x / y;
}
void cal(int(*pf)(int,int))
{
int x = 0;
int y = 0;
printf("输入两个数: ");
scanf("%d %d", &x, &y);
int res = pf(x, y);
printf("%d\n", res);
}
int main()
{
int x = 0;
int y = 0;
int n = 0;
int res = 0;
do
{
menu();
printf("输入: ");
scanf("%d", &n);
switch (n)
{
case 1:
cal(add);
break;
case 2:
cal(sub);
break;
case 3:
cal(mul);
break;
case 4:
cal(div);
break;
default:
break;
}
} while (n);
return 0;
}
回调函数是将一个函数的地址作为参数,传给另一个函数
这个例子中cal (add),为回调函数,将add函数的地址传给cal函数
标签:arr,int,地址,pa,printf,指针 From: https://www.cnblogs.com/xumu11291/p/17040376.html