C语言(指针)

指针的引入

        为函数修改实参提供支持

        为动态内存管理提供支持

        为动态数据结构提供支持

        为内存访问提供另一种途径

指针概述

        内存地址:系统为了内存管理的方便,将内存划分为一个个的内存单元(1个内存单元占1个字节),并为每一个内存单元进行编号,内存单元的编号成为该内存单元的地址,一般情况下,我们每一个变量都是由多个内存单元构成的,所以每个变量的内存地址,其实就是这个变量对应的第一个内存单元的地址,也叫首地址

        变量指针:变量地址称为该变量的指针,变量地址往往是指变量在内存中第一个内存单元的编号(首地址)

        指针变量:存放其他变量地址的变量

        指向:指针变量中存放“谁”的地址,就说明该指针变量指向了“谁”

        “ * ”:指针运算符

/**
  *指针 初识
  */
#include <stdio.h>

void main()
{
    //定义一个普通变量
    int i = 3;
    int *i_point = &i;    //指针变量的数据类型要和存储的地址变量类型一致

    //访问普通变量(直接访问)
    printf("直接访问-%d\n",i);

    //访问指针(地址访问)%p访问地址
    printf("地址访问-%p\n",i_point);

    //访问指针变量(间接访问)
    printf("间接访问-%d\n",*i_point);
}

        指针变量的定义

语法:

数据类型 *变量列表

 举例:

int a;         //普通变量
int *a,*b;    //指针变量

注意:

        1. 虽然定义指针变量 *a ,是在变量名前加上 * ,但是实际变量名为 a ,而不是 *a
        2. 使用指针变量间接访问内存数据时,指针变量必须要有明确的指向;
        3. 如果想借助指针变量间接访问指针变量保存的内存地址上的数据,可以使用指针变量前加 * 来间接访问;
        指针变量前加 * ,也称为对指针变量 解引用
int i = 5,*p;
p = &i;    //将i的地址赋值给指针变量p

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

        4.指针变量只能指向同类型的变量,借助指针变量访问内存,一次访问的内存大小是取决于指针变量的类型

        5.指针变量在定义同时可以初始化,这一点和普通变量是一样的

指针变量的使用

        指针变量的赋值

//方式1
int a,*p;
p = &a;    //指针变量的值是其他变量的地址

//方式2
int a,*p,*q = &a;
p = q;

        操作指针变量的值

int a,*p,*q = &a;
p = q;

printf("%p",p);    //此时返回的是变量a的地址空间

         操作指针变量指向的值

int a = 6,*q = &a;

printf("%d",*q);    //6

两个有关运算符的使用

        &:取地址运算符。&a是变量a的地址

        *:指针运算符(或乘“间接访问”运算符),*p是指针变量p指向的对象的值

案例:

#include <stdio.h>
void main()
{
    int a,b;
    int *pointer_1, *pointer_2;
    a=100; b=10;
    pointer_1=&a;
    pointer_2=&b;
    printf("a=%d,b=%d\n",a,b);
    printf("pointer_1=%d,pointer_2=%d\n",*pointer_1,*pointer_2);
}

        案例1:

                声明a , b两个一般变量,使用间接存取的方式实现数据的交换?

/**
  *需求:声明a,b两个一般变量,使用间接存取的方式实现数据的交换
  */
#include <stdio.h>

void main()
{
    //声明5个变量
    int a = 3,b = 5,*p_a = &a,*p_b = &b,*p_t;

    //交换前输出
    printf("%d,%d\n",*p_a,*p_b);

    //交换位置
    p_t = p_a;
    p_a = p_b;
    p_b = p_t;
    
    //交换后输出
    printf("%d,%d\n",*p_a,*p_b);
}

案例2:

        指针变量应用,输入a、b两个整数,按先大后小的顺序输出a和b。

#include <stdio.h>

void main()
{
    int a = 3,b = 5,*p_a = &a,*p_b = &b,*p_t;

    if(a < b)
    {
        p_t = p_a;    //操作指针变量,不会影响到数据本身
        p_a = p_b;
        p_b = p_t;
    }
    
    printf("按从大到小输出a,b的值:%d > %d\n",*p_a,*p_b);
}

代码:不推荐

#include <stdio.h>

void main()
{
    int a = 3,b = 5,*p_a = &a,*p_b = &b,*p_t;

    if(a < b)
    {
        *p_t = *p_a;    //操作指针地址指向的内存空间,也就是直接操作变量a
        *p_a = *p_b;
        *p_b = *p_t;
    }
    
    printf("按从大到小输出a,b的值:%d > %d\n",*p_a,*p_b);
}

指针变量做函数参数

        指针变量做函数参数往往传递的是变量的地址(首地址),借助于指针变量间接访问是可以修改实参变量数据的

案例1:

        需求:要求用函数处理,用指针变量作函数的参数

                方式1:交换指向(指向的普通变量的值不变)

#include <stdio.h>

/*需求:指针变量应用,输入a,b两个整数,按先大后小的顺序输出a和b*/
/*自定义函数,实现两个数的比较*/
void swap(int *p_a,int *p_b)
{
    int *p_t;
    //这种写法,只会改变指向,不会改变地址对应空间的数据
    p_t = p_a;
    p_a = p_b;
    p_b = p_t;
    
    printf("%d > %d\n",*p_a,*p_b);     //5 > 3
}
void main()
{
    int a = 3,b = 5;
    if(a < b) swap(&a,&b);

    printf("%d > %d",a,b);//3 > 5
}

                方式2:交换值(指向的普通变量的值改变)

#include <stdio.h>

/*需求:指针变量应用,输入a,b两个整数,按先大后小的顺序输出a和b*/
/*自定义函数,实现两个数的比较*/
void swap(int *p_a,int *p_b)
{
    int t;
    
    t = *p_a;
    *p_a = *p_b;
    *p_b = t;
    
    printf("%d > %d\n",*p_a,*p_b);     //5 > 3
}
void main()
{
    int a = 3,b = 5;
    if(a < b) swap(&a,&b);

    printf("%d > %d",a,b);//5 > 3
}

数组元素的指针(通过指针引用数组)

        数组指针:数组中的第一个元素的地址,也就是数组的首地址

        指针数组:用来存放数组元素地址的数组

//定义一个一般数组
int a[] = {1,2,3};
//使用指针变量存储数组的第一个元素的首地址,也就是数组的首地址
int *p = &a[0];
//在c语言中,由于数组名代表数组的首地址,因此,数组名实际上也是指针
int *p = a;
//意味着&a[0] 等价于 a;
printf("%d\n",*p);

        注意:虽然我们定义了一个指针变量接收了数组地址,但不能理解为指针变量指向了数组,而应该理解为指向了数组的元素

指针的运算

        指针运算:指针变量必须要指向数组的某个元素

序号指针运算说明
1自增:p++,++p,p=p+1让指针变量指向下一个元素
2自减:p--a,--p,p-=1让指针变量指向上一个元素
3加一个数:p+1下一个元素的首地址
4减一个数:p-1上一个元素
5指针相减:p1-p2p1,p2之间相差几个元素
6指针比较:p1<p2前面的指针小于后面的指针

案例:

#include <stdio.h>

int main()
{
    int a[] ={1,3,5,7,9};
    int len = sizeof a / sizeof a[0];
    
    //创建指针变量
    int *p = a;

    for(int i = 0;i < len; i++)
    {
        printf("&d",a[i]);//下标法
        printf("&d",*(a + i));//指针法,无法修改数组,只能读
        printf("&d",*(p + i));//指针法,可读可写

        //printf("%d",*p);等价于上面的写法
        //p++
    }
    printf("\n");
    return 0;
}

案例2:

#include <stdio.h>
int main()
{
    int a[] = {1,2,3,4,5,6,7,8,9};
    
    int *p = a;
    
    p++;
    printf("%d\n",*p);    //元素:2

    int x = *p++;    //先*p,再p++
    printf("%d,%d\n",x,*p);    //元素:2,3

    int y = *(++p);    //先p++,再*p
    printf("%d,%d",y,*p);    //元素:4,4

    (*p)++;    //元素值+1,指针不变
    printf("%d\n",*p);

    return 0;
}

数组名做函数参数

        表现形式:

                1、形参和实参都用数组名

                2、实参用数组名,形参用指针变量

                3、实参形参都用指针变量

                4、实参为指针变量,形参为数组名

void fun(int *p1){}
void main()
{
    //注意:如果实参和形参都是指针,我们的实参需要初始化
    int arr[2] = {23,34};
    int *p0 = arr;
    
    fun(p0);
}

案例:

//需求:将数组a中n个整数按相反顺序存放    

#include <stdio.h>
//数组的反转:数组实现
void inv(int arr[],int len)
{
    //反转思路:将第0和第n-1个进行对调,将第一个和n-2个对调
    //定义循环变量i,临时变量temp
    int i = 0,temp;

    //遍历数组
    for(;i < len / 2;i++)
    {
        //交换
        temp = arr[i];
        arr[i] = arr[len - 1 - i];
        arr[len -1 -i] = temp;
    }
}

//指针实现,const 给变量的数据类型前面添加const,代表这个变量是只读变量
void inv2(int *arr,const int len)
{
     int *i = arr,*j = &arr[len -1],temp;
     //遍历数组
      for(;i < j;i++,j--)
      {
        temp = *i;
        *i = *j;
        *j = temp;
      }
}
int main()
{
    int array[10] = {12,23,45,55,66,77,88,26,34,32};
    int len = sizeof(array)/sizeof(int);

    inv2(array,len);

    //检测是否反转
    for(int i = 0;i < len;i++) printf("%d",array[i]);
    
    printf("\n");

    return 0;
}





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值