C语言基础-指针

指针

指针是什么?

  • 指针(Pointer)是编程语言的一个对象,利用地址,他的值直接指向(points to)存在电脑存储器中另一个地方的值。由于通过地址能够找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”,意思是通过它就能找到以它为地址的内存单元。

指针类型

  • 指针类型决定了指针进行解引用操作的时候,能够访问空间的大小。
  • 指针类型决定了指针的步长

指针的大小与系统的操作位数有关,32位/64位 4byte/8byte

野指针

  • 概念:

    • 指针指向的位置是不可知的(随机的)
  • 造成野指针的原因:

    • 指针未初始化
    • 数组越界
    • 指向了已经释放的指针
  int* test6(){
	   int a = 0;
	   return &a;
	  }
 int main(){
   
   int* c = test6();
   printf("%d",*c);
   
   return 0;
  }
  • 如何避免野指针:

    • 指针初始化
    • 小心指针越界
    • 及时将释放了的指针指向NULL
    • 使用指针前检查其有效性

内存泄漏

  • 造成的原因:

    • 指向内存区域的指针的值发生了改变

指针运算

  • 指针±整数

    • 其数据类型决定了指针在内存中走多远(多少个字节)
int arr[] = {1,2,34,5,6,7,8,9,10};
for(int i =0;i<10;i++){
  printf("%d"*(p+i));
}
  • 指针-指针

    • 在两个指针指向同一个内存单元,指针-指针得到的是指针地址之间的元素个数。

      • 例题一:
  int test7(char * str){
	 //求字符数组的元素个数
	   char* start = str;
	   char* end = str;
	   while (*end != '\0'){
	   end++;
	   }
  	 return end - start;
  }
  int main(){
  
	   char arr[] = "qwdcsvz";
	   printf("%d", test7(arr));
	  
	   return 0;
  }
  • 指针的关系运算

指针和数组

  • 数组名是首元素的地址

  • 数组名不是数组首元素地址的是:

    • &arr

      • 整个数组的地址
    • sizeof(arr)

      • 整个数组
    • 二维数组

      • 第一个一维数组的地址
    • 以及二维以上数组

  • 注意:允许最后一个数组元素后面的那个内存地址进行比较,但不允许首元素前一个内存地址进行比较。

二级指针

  • 存放一级指针地址的指针

指针数组

  • 存放指针地址的数组
    • 如果指针数组内存放的是指针,则需要两次解引用才能访问其值。
 //指针数组
void test3(){

	int a = 1;
	int b = 2;
	int c = 3;

	int* p[3] = { &a, &b, &c};

	int i = 0;
	for (i = 0; i < 3; i++){

		printf("%d ", *(p+i));
		printf("\n");
	}
}

数组指针

  • 存放指针数组地址的指针

    • //数组指针
	int arr[6] = { 1, 2, 3, 4, 5, 6 };
	int(*p)[6] = &arr;
// int 为指向数组的元素类型
//(*p)指的是 指针变量p
//[6] 指的是指针指向的数组有6个元素
  • 主要用二维及以上的数组传参使用

指向数组指针的指针数组

  • //指向数组指针的指针数组
	int arr1[6] = { 1, 2, 3, 4, 5, 6 };
	int arr2[6] = {  2, 3, 4, 5, 6,7 };
	int arr3[6] = {   3, 4, 5, 6,7,8 };

	//数组指针
	int (*pArr1)[6] = &arr1;
	int (*pArr2)[6] = &arr2;
	int (*pArr3)[6] = &arr3;

	//指向数组指针的指针数组
	int(*p[3])[6] = { pArr1, pArr2, pArr3 };

	//指向数组指针的指针数组的指针
	int(*(*ps)[3])[6] = &p;

	printf("%d",*(*(p+1)+1));

字符指针

  • char arr[] = “abcdef”;

    • 实际将除了字符串内容放到字符数组内外,还将\0放到了字符数组的末尾
  • char* arr = “abcdef”;

    • 实际将常量字符串a的地址放在了字符指针arr中
    • 注意: 此时不可通过间接引用修改*arr的值
    • 最好使用一下写法:
      const char* arr = “abcdef”;
  • 例题:

    • ①:相同的字符串的数组名相比较是否相同
    • ②:比较相同字符串的字符指针否相同
	  //判断两值是否相同 
  char arr1[] = "abcdefg";
  char arr2[] = "abcdefg";
  
   char* p1 = "abcdefg";
   char* p2 = "abcdefg";
  
   if (arr1 == arr2){
   printf("haha");
   }
   else{
   printf("hehe");
   }
//结果是“hehe”
  //判断两值是否相同
   char arr1[] = "abcdefg";
   char arr2[] = "abcdefg";
  
   char* p1 = "abcdefg";
   char* p2 = "abcdefg";
  
   if (p1 == p2){
   printf("haha");
   }
   else{
   printf("hehe");
   }
//结果是“haha”

指针作为函数参数

  • 一级指针char* arr可以接收什么样类型的数据

    • ①:一级指针变量
    • ②:char类型变量的地址(&变量名)
  • 二级指针char** arr可以接收什么样类型的数据

    • ①:二级指针变量
    • ②:一级指针变量的地址
    • ③:字符指针数组的地址。

const 修饰指针变量

  • const int* p

    • 指针所指向的值不能发生改变
    • 不能通过(*p)修改指向内存单元内的值
  • int* const p

    • 指针的值不能发生改变
    • 不能修改指针边内指向的地址

函数指针

  • 定义:指向函数的指针称为函数指针。

  • 函数指针的声明:

    • 返回值类型 (*函数指针名) (函数参数列表) = 函数名
  • ((void ()())0)()

    • 该式子为将整型0转换为函数指针,然后解引用地址0,并调用该函数,参数为空。
  • void (* signed(int,void (*)()))(int);

    • 其实是一个函数声明,函数signed为两个参数int、函数指针的函数,返回值为函数指针。
  • 函数指针的调用:

    • int(*p)(int) = test5;
      //其结果都是一样的。
      printf("%d “, (*p)(5));
      printf(”%d “, (**p)(5));
      printf(”%d “, (*p)(5));
      //函数指针也可以不带
      调用,但带
      必须与指针变量在一个小括号内
      printf(”%d ", p(5));
      5 5 5 5 请按任意键继续. . .
  • 函数指针数组

    • int(*p[5])()

    • 案例:计算器

      • 方法一: 普通调用
      • 方法二:(转移表)
	 //计算机入口 方法一

int Add(int x ,int y){
	return x + y;

}

int Min(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 test6(){
   int input = 0;
  
   int(*func[4])(int, int) = {Add,Min,Mul,Div};
   do{
   menu();
   printf("请输入功能按键>");
   scanf("%d", &input);
   int x = 0, y = 0;
   switch (input){
   case 1:printf("请输入两个操作数,空格隔开>");
   
   scanf("%d %d", &x, &y); printf("%d\n", func[0](x, y)); break;
   case 2:printf("请输入两个操作数,空格隔开>");
   
   scanf("%d %d", &x, &y); printf("%d\n", func[1](x, y)); break;
   case 3:printf("请输入两个操作数,空格隔开>");
  
   scanf("%d %d", &x, &y); printf("%d\n", func[2](x, y)); break;
   case 4:printf("请输入两个操作数,空格隔开>");
  
   scanf("%d %d", &x, &y); printf("%d\n", func[3](x, y)); break;
   case 0:break;
   default:printf("输入有误,请重新输入!\n"); break;
   }
  
   } while (input);
   printf("程序退出。\n");
  
  }
 //计算机入口 方法二
 int Add(int x ,int y){
	return x + y;

}

int Min(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 test7(){
  	int input = 0;
  
  	int(*func[])(int, int) = { 0,Add, Min, Mul, Div };
  	do{
  		menu();
  		printf("请输入功能按键>");
  		scanf("%d", &input);
  		int x = 0, y = 0;
  		
  		if (input > 0 && input <= sizeof(func) / sizeof(func[0])){
  			printf("请输入两个操作数,空格隔开>");
  			scanf("%d %d", &x, &y);
  			printf("%d\n", func[input](x, y));
  		}else
  		if (input == 0){
  			printf("程序退出。\n");
  		}
  		else{
  			printf("输入有误,请重新输入!\n");
  		}
  	
  		
  
  	} while (input);
  
  }
  • 回调函数

    • 回调函数就是一个通过指针调用的函数。当一个函数当做实参传递给另一个函数时,另一个函数通过该函数指针调用其指向的函数时,我们程为回调函数。
  • 指向函数指针数组的指针

    • int fun(int x,int y){
      return x + y;
      }
      函数指针数组
      int (p[3])(int,int) = {fun1,fun2,fun3};
      函数指针数组的指针
      int (
      (*p)[3])(int,int) = &p;
      指针p指向一个元素为3的数组,元素类型为返回值类型int,参数为2个int类型的函数。

void * 指针

  • void*指针为通用指针(无类型指针),可以接收任意类型的指针
  • void* 不能解引用操作
  • void* 不能进行±整数操作

利用回调函数机制写万能排序函数

点击链接:手写万能排序的思路

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值