内存
⼀个⽐特位可以存储⼀个2进制的位1或者0
1byte = 8bit 1KB = 1024byte 1MB = 1024KB
1GB = 1024MB 1TB = 1024GB 1PB = 1024TB
解引用操作符(*)
char* short* int* double* 为指针变量大小为4或8个字节
指针变量类型的意义
指针变量的⼤⼩和类型⽆关,只要是指针变量,在同⼀个平台下,⼤⼩都是⼀样的
指针的解引用
#include <stdio.h>
int main()
{
int n = 0x11223344;
int *pi = &n;
*pi = 0;
return 0;
}
#include <stdio.h>
int main()
{
int n = 0x11223344;
char *pc = (char *)&n;
*pc = 0;
return 0;
}
代码二:(char*)&n中的 (char*)的作用为强转char*
指针+-整数
#include <stdio.h>
int main()
{
int n = 10;
char *pc = (char*)&n;
int *pi = &n;
printf("%p\n", &n);
printf("%p\n", pc);
printf("%p\n", pc+1);
printf("%p\n", pi);
printf("%p\n", pi+1);
return 0;
}
00QSS878 |
00QSS878 |
00QSS879 |
00QSS878 |
00QSS882 |
char* 类型的指针变量+1跳过1个字节, int* 类型的指针变量+1跳过了4个字节。 这就是指针变量的类型差异带来的变化
void* 指针
void* 类型的指针可以接收不同类型的地址,但是⽆法直接进⾏指针运算
const修饰指针
const修饰变量
const int n = 0;
printf("n = %d\n", n);
int*p = &n;
*p = 20;
printf("n = %d\n", n);
被const修饰后n不可被修改但利用n的地址认可修改
const修饰指针变量
const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。 但是指针变量本⾝的内容可变
const如果放在*的右边,修饰的是指针变量本⾝,保证了指针变量的内容不能修改,但是指针指 向的内容,可以通过指针改变
指针运算
指针+-整数
*(p+i)相当于arr[i]
指针-指针
相同类型连续的指针相减得出 n个指针类型的大小
野指针
导致野指针出现的情况
1
int *p;//局部变量指针未初始化,默认为随机值
2
指针指向的范围超出数组arr的范围时,p就是野指针
3
指针指向的空间释放
int* test()
{
int n = 100;
return &n;
}
int main()
{
int*p = test();
printf("%d\n", *p);
return 0;
}
在函数调用完之后变量n所在的空间又还给了操作系统
规避野指针
1
指针初始化
NULL 是C语⾔中定义的⼀个标识符常量,值是0,0也是地址,这个地址是⽆法使⽤的,读写该地址 会报错
int*p2 = NULL;
2
警惕越界访问
3
指针使⽤之前检查有效性
p = NULL;
if(p != NULL) //判断
{
//...
}
4
不要返回局部变量的地址
assert断⾔
头文件 <assert.h>
⽤于在运⾏时确保程序符合指定条件,如果不符合,就报错终⽌运⾏。这个宏常常被称为“断⾔”
——
assert(p != NULL);
验证变量 p 是否等于 NULL 。如果确实不等于 NULL ,程序 继续运⾏,否则就会终⽌运⾏,并且给出报错信息提⽰。
——
真反1,假反0
定义宏:#define NDEBUG 可以将assert()
指针的使⽤和传址调⽤
实参传递给形参的时候,形参会单独创建⼀份临时空间来接收实参,对形参的修改不影响实参
传址调⽤,可以让函数和主调函数之间建⽴真正的联系,在函数内部可以修改主调函数中的变量
数组名的理解
数组名为数组首元素的地址
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("&arr[0] = %p\n", &arr[0]);
printf("arr = %p\n", arr);
return 0;
}
&arr[0]=004FF9CC
arr =004FF9CC
——————
***特例*** :
• sizeof(数组名),sizeof中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩, 单位是字节
• &数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素 的地址是有区别的)
——————
指针,指针类,种类
二级指针
int a=20;
int *pa=&a;
int **paa=&pa;
**paa=30
结果:a=30
指针数组
指针数组的每个元素是地址,⼜可以指向⼀块区域
模拟二维数组int* parr[3] = {arr1, arr2, arr3};
printf("%d ", parr[i][j]);
数组指针
------------------------------
int (*p)[10]=&arr;
(*p)[1]=1;
二维数组指针传参
#include <stdio.h>
void test(int (*p)[5], int r, int c)
{
int i = 0;
int j = 0;
for(i=0; i<r; i++)
{
for(j=0; j<c; j++)
{
printf("%d ", *(*(p+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}};
test(arr, 3, 5);
return 0;
}
⼆维数组传参本质上也是传递了地址,传递的是第⼀ ⾏这个⼀维数组的地址
⼆维数组传参,形参的部分可以写成数组,也可以写成指针形式。
------------------------------
#include <stdio.h>
int main()
{
int arr1[3] = { 4,5,6 };
int arr2[3] = { 1,2,3};
int arr3[5] = { 1,3,5,4,5};
int* parr[3] = { arr1, arr2, arr3 };
int*(*p)[3] = &parr;
printf("%d",(*p)[1][1]);
return 0;
}
字符指针
char ch='w';
char* ch=&ch;
函数指针
printf("test: %p\n", test); test: 005913CA
printf("&test: %p\n", &test); &test: 005913CA
创建函数指针变量
void test()
{
printf("hehe\n");
}
void (*pf1)() = &test;
void (*pf2)()= test;
int Add(int x, int y)
{
return x+y;
}
int(*pf3)(int, int) = Add;
int(*pf3)(int x, int y) = &Add;//x和y写上或者省略都是可以的
函数指针数组
int (*parr1[3])();
typedef关键字
typedef 是⽤来类型重命名的
typedef unsigned int uint; //将unsigned int 重命名为uint
typedef int* ptr_t; //将int*重命名为ptr_t
但是对于数组指针和函数指针稍微有点区别:
typedef void(*pfun_t)[5]; //将int(*)[5]重命名为parr_t
typedef void(*pfun_t)(int); //将 void(*)(int) 重命名为 pfun_t
简化代码: typedef void(*pfun_t)(int);
pfun_t signal(int, pfun_t);
转移表
int(*p[5])(int x, int y) = { 0, add, sub, mul, div };
ret = (*p[input])(x, y);
回调函数
void calc(int(*pf)(int, int))
{
int ret = 0;
int x, y;
printf("输⼊操作数:");
scanf("%d %d", &x, &y);
ret = pf(x, y);
printf("ret = %d\n", ret);
}
case 1:
calc(add);
break;
case 2:
calc(sub);
break;
case 3:
calc(mul);
break;
case 4:
calc(div);
break;
case 0:
printf("退出程序\n");
break;
default:
printf("选择错误\n");
break;
qsort
qsort函数排序整型数据
头文件<stdlib.h>
qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp);
接收4个参数:一(数组名),二(数组长度),三(类型大小),四(比较函数)
比较函数:
int int_cmp(const void * p1, const void * p2)
{
return (//自写);
}