C语言——关于指针

 

思维导图

一、指针的基础知识

1.指针的定义

    地址

            在存储时,内存被分为一块一块的。每一块都有一个特有的编号。而这个编号可以暂时理解为地址,就像⽣活中我们把⻔牌号也叫地址,在计算机中我们 把内存单元的编号也称为地址。C语⾔中给地址起了新的名字叫:指针。

            所以我们可以理解为: 内存单元的编号 == 地址 == 指针

    指针变量的大小

            32位平台下地址是32个bit位,指针变量⼤⼩是4个字节

            64位平台下地址是64个bit位,指针变量⼤⼩是8个字节

    取地址操作符(&)   

            取地址操作符的作用就和它的名字一样:获取所需内容的地址。

      解引用操作符(*)

               我们拿到了地址(指针),就可以通过地址(指针)找到地址(指针)指向的对象,这⾥用到的操作符叫解引⽤操作符(*)。

                 上⾯代码中就使⽤了解引⽤操作符, *pa 的意思就是通过pa中存放的地址,找到指向的空间, *pa其实就是a变量了;所以*pa = 0,这个操作符是把a改成了0。

2.指针运算

    指针+-整数

                  实例:                

       指针-指针

                  实例:

       void*指针

                  在指针类型中有⼀种特殊的类型是 void* 类型的,可以理解为⽆具体类型的指针(或者叫泛型指针),这种类型的指针可以⽤来接受任意类型地址。但是也有局限性, void* 类型的指针不能直接进 ⾏指针的+-整数和解引⽤的运算。

     3.const修饰指针

         const修饰变量

                   const的作用:使修饰的变量无法更改。

          const修饰指针变量

                   const在修饰指针变量时在*的位置不同作用效果也不同。

                   const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。但是指针变量本⾝的内容可变。

                   const如果放在*的右边,修饰的是指针变量本⾝,保证了指针变量的内容不能修改,但是指针指向的内容,可以通过指针改变。

    4.野指针

                   概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)。

        野指针的成因

                  1)指针未初始化

                  2)指针越界访问

                   3)指针指向的空间释放

 

           如何规避野指针 

                   1)指针初始化

                   2)小心越界访问

                   3)指针变量不再使⽤时,及时置NULL,指针使⽤之前检查有效性

    5.assert断言

                   assert.h 头⽂件定义了宏 assert() ,⽤于在运⾏时确保程序符合指定条件,如果不符合,就报错终⽌运⾏。这个宏常常被称为“断⾔”。

                   assert() 的缺点是,因为引⼊了额外的检查,增加了程序的运⾏时间。

     6.指针的使用和传址调用

          strlen的模拟实现

                   库函数strlen的功能是求字符串⻓度,统计的是字符串中 \0 之前的字符的个数。

           传值调用和传址调用

                      传址调⽤,可以让函数和主调函数之间建⽴真正的联系,在函数内部可以修改主调函数中的变量;所以未来函数中只是需要主调函数中的变量值来实现计算,就可以采⽤传值调⽤。如果函数内部要修改主调函数中的变量的值,就需要传址调⽤。

 二、数组中的指针

      1.数组名的理解

                        数组名就是数组⾸元素(第⼀个元素)的地址。

                        sizeof(数组名),sizeof中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩, 单位是字节

                        &数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素的地址是有区别的)

                         除此之外,任何地⽅使⽤数组名,数组名都表⽰⾸元素的地址。

        2.使用指针访问数组

                          有了前⾯知识的⽀持,再结合数组的特点,我们就可以很⽅便的使⽤指针访问数组了。

       3.一维数组传参的本质 

                               本质上数组传参本质上传递的是数组⾸元素的地址。

                              ⼀维数组传参,形参的部分可以写成数组的形式,也可以写成指针的形式。

        4.冒泡排序

                              冒泡排序的核⼼思想就是:两两相邻的元素进⾏⽐较。

void Bubble_sort(int arr[], int sz)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < sz - 1; i++)
	{
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}

int main()
{
	int arr[10] = { 9,5,6,3,7,1,4,2,8,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	Bubble_sort(arr, sz);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

          5.二级指针

                               是一个指针变量,指向一个一级指针,并保存该一级指针的地址;

         6.指针数组 

                              指针数组的每个元素都是⽤来存放地址(指针)的。      

         7.指针数组模拟二维数组

 三、函数中的指针

          1.字符指针变量

                       在指针的类型中我们知道有⼀种指针类型为字符指针 char* ;

                       ⼀般使⽤:

int main()
{
 char ch = 'w';
 char *pc = &ch;
 *pc = 'w';
 return 0;
}

                        还有⼀种使⽤⽅式如下:

int main()
{
 const char* pstr = "hello bit.";
 printf("%s\n", pstr);
 return 0;
}

           2.数组指针变量

                        整形指针变量: int * pint; 存放的是整形变量的地址,能够指向整形数据的指针。

                        浮点型指针变量: float * pf; 存放浮点型变量的地址,能够指向浮点型数据的指针。

                        那数组指针变量应该是:存放的应该是数组的地址,能够指向数组的指针变量。

                        数组指针变量: p先和*结合,说明p是⼀个指针变量变量,然后指着指向的是⼀个⼤⼩为10个整型的数组。所以p是⼀个指针,指向⼀个数组,叫数组指针。

这⾥要注意:[]的优先级要⾼于*号的,所以必须加上()来保证p先和*结合。

            3.二维数组传参本质

                         ⼆维数组传参本质上也是传递了地址,传递的是第⼀⾏这个⼀维数组的地址。

#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;
}

            4.函数指针变量

                         函数指针变量应该是⽤来存放函数地址的,未来通过地址能够调⽤函数的。

#include <stdio.h>
int Add(int x, int y)
{
 return x+y;
}
int main()
{
 int(*pf3)(int, int) = Add;
 
 printf("%d\n", (*pf3)(2, 3));
 printf("%d\n", pf3(3, 5));
 return 0;
}

             5.函数指针数组

                         所谓函数指针数组,就是一个存放函数指针的数组。

            6.函数指针数组的⽤途:转移表

                         举例:计算器的⼀般实现:

#include <stdio.h>
int add(int a, int b)
{
 return a + b;
}
int sub(int a, int b)
{
 return a - b;
}
int mul(int a, int b)
{
 return a * b;
}
int div(int a, int b)
{
 return a / b;
}
int main()
{
 int x, y;
 int input = 1;
 int ret = 0;
 do
 {
 printf("*************************\n");
 printf("    1:add      2:sub     \n");
 printf("     3:mul      4:div     \n"); 
 printf("    0:exit               \n");
 printf("*************************\n");
 printf("请选择:");
 scanf("%d", &input);
 switch (input)
 {
 case 1:
 printf("输⼊操作数:");
 scanf("%d %d", &x, &y);
 ret = add(x, y);
 printf("ret = %d\n", ret);
 break;
 case 2:
 printf("输⼊操作数:");
 scanf("%d %d", &x, &y);
 ret = sub(x, y);
 printf("ret = %d\n", ret);
 break;
 case 3:
 printf("输⼊操作数:");
 scanf("%d %d", &x, &y);
 ret = mul(x, y);
 printf("ret = %d\n", ret);
 break;
 case 4:
 printf("输⼊操作数:");
 scanf("%d %d", &x, &y);
 ret = div(x, y);
 printf("ret = %d\n", ret);
 break;
 case 0:
 printf("退出程序\n");
 break;
 default:
 printf("选择错误\n");
 break;
 }
 } while (input);
 return 0;
}

     四、回调函数

              1.什么是回调函数

                          回调函数就是⼀个通过函数指针调⽤的函数。

                          举例:

                     2.qsort使用实例

                                     使用qsort函数排序整形数据

                                     使用qsort排序结构数据

     五、总结 

                       以上内容不仅是对知识点的总结,也是对我近期学习状况的总结,感谢各位的观看。

  • 26
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值