C语言指针

本文详细介绍了C语言中的指针概念,包括指针的长度、类型、意义和常见问题。指针长度与机器位数相关,类型取决于所指向变量类型。指针用于访问和修改不同长度的数据,其步长与指针类型有关。文章还讨论了野指针、越界访问等错误及规避方法,并通过实例解析了指针运算、数组与指针的关系、指针数组、数组指针和函数指针等高级主题。
摘要由CSDN通过智能技术生成
  •  指针:指针也就是内存地址,指针变量是用来存放内存地址的变量,在同一CPU构架下,不同类型的指针变量所占用的存储单元长度是相同的,而存放数据的变量因数据的类型不同,所占用的存储空间长度也不同。有了指针以后,不仅可以对数据本身,也可以对存储数据的变量地址进行操作。

      个人理解: 指针就是个存放地址的变量。        


  •  指针长度:32位机器,有32根地址线,每根地址线都产生一个电信号(1/0),共有32位,所以需要4字节来存储地址。64位机器则需要8字节。
  • 指针的类型:指针的类型取决于它指向的地址装的变量类型,定义指针只需要将指针类型设为“变量类型*”即可。

        例如:                                        

       

        #include<stdio.h>
        int main()
        {
            int a = 1;
            int* p = &a;//Int*类型的指针指向a,&a表示取出a的地址。
            printf("%d\n", *p);//*p表示找到p指针里装的变量。
            return 0;
        }
  • 指针的意义:既然指针大小只跟计算机处理器有关系为什么要设计指针的类型?而不是统一用同一个类型?                

      指针的类型决定了指针可以访问的内存大小及其步长(指针+1的位置)

  1. 步长实例:
#include<stdio.h>
int main()
{
	int a = 1;
	int* p = &a;
	char* pc = (char*)&a;
	printf("%p\n", p);
	printf("%p\n", p+1);
	printf("%p\n", pc);
	printf("%p\n", pc+ 1);
	return 0;
}

        上列代码输出结果:

   

  由输出结果我们可以知道指针类型不同,指针的步长也不相同,char*类型指针步长为1(char长度),int*类型步长为4(int长度)。

        2.指针访问地址实例:

int main()
{
	int n = 0x11223344;
	char* pc = (char*)&n;
	int* pi = &n;
	*pc = 0; 
	*pi = 0; 
	return 0;
}

 一步步调试:

n初始化:

用char*指针改变变量n的值,只改了一位。 用int*指针改变变量n的值,改了4位。

结论:不同的指针类型可以读取/修改不同的长度,它们的步长大小也不相同。


  • 指针在使用中经常会有使用不当,造成报错的情况,下面总结一下经常出现的问题:
  1. 野指针,指针未初始化
    int main()
    { 
     int *p;//局部变量指针未初始化,默认为随机值
     *p = 20;
     return 0;
    }
  2. 指针越界访问
    int main()
    {
        int arr[10] = {0};
        int *p = arr;
        int i = 0;
        for(i=0; i<=11; i++)
       {
            //当指针指向的范围超出数组arr的范围时,p就是野指针
            *(p++) = i;
       }
        return 0;
    }

  3. 指针指向的空间释放

  •  如何规避野指针
    1. 指针初始化
    2. 小心指针越界
    3. 指针指向空间释放即使置 NULL
    4. 指针使用之前检查有效性
    int main()
    {
        int *p = NULL;
        //....
        int a = 10;
        p = &a;
        if(p != NULL)
       {
            *p = 20;
       }
        return 0;
    }

    • 指针的运算
    1. 指针可以加减整数(得到的结果是指针)
      int main()
      	{
      		int a[10] = { 0,1,2,3,4,5,6,7,8,9 };
      		int i;
      		for (i = 0; i < 10; i++)
      		{
      			printf("%d\t", *a + i);//其实就是打印a[i],每次加1指针都向后走4位。
      		}
      		return 0;
      	}

      运行结果

    2. 指针可以-指针(得到的结果是数字)

      int main()
      {
      	char a[10] = "abcde";
      	char* tmp = a;
      	while (*tmp != '\0')//找到\0位置
      	{
      		tmp++;
      	}
      	printf("%d\n", tmp - a);//结果是字符串长度
      	return 0;
      }

       运行结果:

                    

     


    • 指针和数组:数组名就是数组首地址,两种情况除外:
    1. sizeof(a)    //a是数组名,这种情况取得是整个数组的长度。
    2. &a     //a是数组名,这种情况取得是整个数组的地址,尽管数组地址和数组首元素地址相同,但是步长不同。
      int main()
      {
      	char a[10] = "abcde";
      	printf("%p\n",&a);
      	printf("%p\n",&a[0]);
      	printf("%p\n", &a+1);
      	printf("%p\n", &a[0] + 1);
      
      	return 0;
      }

      运行结果:

                    

                     由运行结果可知:数组地址和首元素地址是相同的,但是&a+1和&a[0]+1结果不同,&a+1是数组首元素地址向后移动10位(步长是整个数组的长度),&a[0]+1是首元素地址向后移动1位(移动一个sizeof(char)字节)。

    • 指针数组(装数组的指针):int* a[n],表示有一个数组a,里面可以存放n个类型为int*的变量。
    • 数组指针:指向数组的指针:int(*p)[3],表示指针p指向一个长度为3,存放数据类型为int的数组。
      #include<stdio.h>
      void f(int (*a)[3], int n, int m)//a是一个指向长度为3,里面数据类型为int的数组的指针。
      {
      	int i, j;
      	for (i = 0; i < n; i++)
      	{
      		for (j = 0; j < m; j++)
      		{
      			printf("%d\t",a[i][j]);
      		}
      		printf("\n");
      	}
      }
      int main()
      {
      	int a[2][3] = { 0,1,2,3,4,5 };
      	f(a, 2, 3);
      
      	return 0;
      }

      运行结果:

            


    练习:

    int arr [ 5 ];                                 一个装有5个int类型变量的数组
    int * parr1 [ 10 ];                          一个装有10个int*类型变量的数组
    int ( * parr2 )[ 10 ];                        一个指向装有10个int类型变量的数组的指针
    int ( * parr3 [ 10 ])[ 5 ];                   一个装有10个int*[5]数组的数组emmmm

    • 一维数组传参的写法:(假设int a[10]要作为f的参数)

           int f(int* a)   //a就是数组首地址

           int f(int a[10])

           int f(int a[])

    • 二维数组传参时可以省略第一个[]里的值,但是第二个[]的值不能省略,因为第二个值是宽度,省略了 的话没法儿放。

          int f(int a[][3])      //可以

          int f(int a[][])      //NO NO NO


    • 函数指针:指向函数的指针

           int f(int a)的指针:int (*p)(int)

    • 函数指针数组:装有函数指针的数组

            int (*p[])(int)


    • 回调函数:把一个函数作为参数传递给另一个函数,并在需要的时候执行这个函数。

        qsort函数的使用:

         qsort是一个系统函数,功能是用快速排序实现任何类型数据的排序。

       先用man看一下它参数都是啥

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值