C语言常见指针

指针

  • 内存编址:每个字节都有唯一的编号 (地址)
  • 地址为无符号整数,16进制
  • 指针不是地址,指针变量的值是一个地址
  • 可以保存变量、数组、字符串的首地址,保存函数的入口

定义

  • 基类型 *变量;
  • 基类型:指针变量指向的数据类型
  • %p:输出变量地址
  • 指针变量使用前必须初始化
    • 不知道指向那里,就指向NULL
  • 初始化:
    • 基类型 *变量1=&变量2
    • 基类型 *变量1;变量1=&变量2
#include <stdio.h>
#include <stdlib.h>
int main()
{
    int a=1;
    //int *pa;//定义指针
    int *pa=&a;//指针初始化;
    //int *pa=NULL;//指针初始化
    //pa=NULL;//指针初始化
    printf("%d\n", a);
    printf("&a=%p\n",&a);
    printf("pa=%p\n",pa);
}

空指针

  • 值为NULL的指针

指针解引用

  • 通过间接寻址运算符访问指针指针指向变量的值
  • 在指针变量说明中,“”是类型说明符,表示其后的变量是指针类型,而表达式中出现的“”则是一个运算符用以表示指针变量所指的变量。
  • 基类型 *变量=&变量1;
    • *变量=变量2;
    • 说明:*变量为变量1的别名,可以赋值
#include <stdio.h>
#include <stdlib.h>
int main()
{
    int a=0;
    int *pa=&a;//指针初始化;
    *pa=1;//给a赋值
    printf("a=%d\n", a);
    printf("*p=%d\n",*pa);//等价上一条语句
    return 0;
}

指针变量作为函数参数

在这里插入图片描述

  • 可以通过实参变量的地址,进而改变指针形参的值
  • 这样函数可以返回多个值。
  • 提供了修改实参值得方法
#include <stdio.h>
void Fun(int *par);//函数指针
int main()
{
    int a=1;
    printf("a=%d\n" ,a);
    Fun(&a);//传递地址
    printf("a=%d\n",a);
    return 0;
}

void Fun(int *par)
{
    printf("a=%d\n",*par);
    *par=2;
}

案例

  • 两数交换
    • 可以直接将值传给实参
    • 不能借助一个未初始化得指针变量进行两数交换
#include <stdio.h>
void Swap(int *x,int *y);
int main()
{
    int a=5,b=9;
    Swap(&a,&b);
    printf("a=%d,b=%d",a,b);
    return 0;
}

void Swap(int *x,int *y)//两数交换
{
    int temp;
    temp=*x;
    *x=*y;
    *y=temp;
}

函数指针

  • 格式:数据类型 (*指针变量名)(形参列表);
  • 作用
    • 编写 通用性更强的函数
    • 实例1:通用计算任意函数定积分得函数
    • 实例2:通用的排序函数
    • 方便直接在主函数调用其他函数
int Max(int x,int y);

int (*f)(int,int);//声明了函数名为f,返回值是整型指针类型得函数;在main里面
f=Max;//Max是定义得函数名
result=(*f)(a,b);//调用赋值

案例

#include <stdio.h>
void Fun(int x,int y,int (*f)(int,int));
int Max(int x,int y);
int Min(int x,int y);
int Add(int x,int y);
int main()
{
    int a,b,result;
    int (*f)(int,int);
    printf("请输入:\n");
    scanf("%d,%d",&a,&b);
    Fun(a,b,Max);
    Fun(a,b,Min);
    Fun(a,b,Add);
    return 0;
}

void Fun(int x,int y,int (*f)(int,int))//直接输出
{
    int result;
    result=(*f)(x,y);
    printf("%d\n",result );
}

int Max(int x,int y)//判断最大数
{
    printf("max=");
    return x>y?x:y;
}

int Min(int x,int y)//判断最小数
{
    printf("min=");
    return x<y?x:y;
}

int Add(int x,int y)//计算总和
{
    printf("sum=");
    return x+y;
}

指向指针的指针

  • 如果一个指针变量存放的又是另一个指针变量的地址,则称这个变量为指向指针的指针变量或指向指针的指针。

  • 定义方式: 数据类型 **变量名;

  • 在指针变量说明中,“”是类型说明符,表示其后的变量是指针类型,而表达式中出现的“”则是一个运算符用以表示指针变量所指的变量。

int a=10;        //地址为&a
int *p=&a;        //指针地址为&p    如果是p就是a的地址
int **p1=&p;        //指针地址为&p1     如果是*p1就是&p</span>
#include<stdio.h>
#include<stdlib.h>
int main()
{
    const char *s[]={"man","woman","girl","boy","sister"};
    const char **q;//定义指向指针的指针变量
    int k;
    for(k=0;k<5;k++)
    {
        q=&s[k];       /*在这里填入内容*/
        printf("%s\n",*q);//*p指的对应地址的内容
    }
    return 0;
}

指针和数组

  • 可以用指针代替数组下标操作

算数运算

  • 加上整数,减去整数,两个指针相减
  • 参与运算:加,减整数,自增,自减,关系,赋值

指针指向数组元素才有意义

  • p+j不是加j个字节,而是取决于p的基类型
  • 指向同一数组时,还可以比较
#include <stdio.h>
int main()
{
    int a[10];
    int *p,*q;
    p=&a[i];
    q=p+j;
    q=p-j;
}

指针与一维数组

首地址&a[0]

  • &a[i]等价于(a+i)
  • a+1指的是:a+i*sizeof(基类型)
  • 数组地址的相差取决于基类型
#include <stdio.h>
int main()
{
    int a[5],*p=NULL;
    for(p=a;p<a+5;p++)
    {
        scanf("%d",p);
    }
    for(p=a;p<a+5;p++)
    {
        printf("%4d\n",*p);
    }

}


自加区别

  • *p++是指下一个地址。

  • (*p)++是指将星p所指的数据的值加一。

//*p++与(*p)++区别
#include <stdio.h>
int main()
{
    int x,y,a[]={1,2,3,4,5},*p=a,*q=a;
    printf("%d\n",*p );
    x=*p++;//执行这一句后x=a[0]=1,p=a+1
    printf("%d\n",x);
    y=(*q)++;//执行这一句后,y=a[0]+1=2,q仍然=a
    printf("%d\n",y );
}

指针与二维数组

指向二维数组的行指针

定义
  • int (*p)[3];//行指针,基类型int[3]类型
  • int *q[3];//指针数组
int a[2][3];
//a[i][j]的元素值等价于*(*(p+i)+j)
//*(p+i),即a[i],指向第i行第0列的int型元素
//*(p+i)+j指向第j行第j列的int型元素
//*(*(p+i)+j)取出第i行第j列的内容,即a[i][j]

实例
  • 按行查找,再按列查找
#include <stdio.h>
int main()
{
    int i,j;
    int a[2][3]={1,2,3,4,5,6};
    int (*p)[3];//行指针,基类型int[3]类型 
    p=a;//&a[0]指向第0行的int[3]型元素
    for(i=0;i<2;i++)//行下标变化
    {
        for(j=0;j<3;j++)//列下标变化
        {
            printf("%d\n",*(*(p+i)+j));
        }
    }
}


指向二维数组的列指针

定义
  • int *p;//列指针,基类型是int 型
  • 将二维看成一维数组
int *p;
p=&a[0][0];//*(a+0)+0)即&a[0][0],指向a[0][0]的int元素
*(p+i*3+j)//代表着第一个元素,i代表前i行,j代表着本行第j个元素

在这里插入图片描述

实例
#include <stdio.h>
int main()
{
    int i,j;
    int a[2][3]={1,2,3,4,5,6};
    int *p;
    p=&a[0][0];//*(a+0)+0)即&a[0][0],指向a[0][0]的int元素
    for(i=0;i<2;i++)
    {
        for(j=0;j<3;j++)
        {
            printf("%d\n",*(p+i*3+j));
        }
    }
}


指针数组

二维字符数组

  • 第二维下标不能省略
  • 相对字符指针数组空间浪费
  • 定义:char country[][10]={“A”,“E”,“A”,“C”,“j”};
#include <stdio.h>
int main()
{
    int i;
    char country[][10]={"America","England","Australia","China","a"};//定义二维字符数组
    for(i=0;i<5;i++)
    {
        printf("%s\n",country[i]);//访问数组,输出每行的内容
    }

}

字符指针数组

  • 每个数组元素都是一个指向字符串的指针
  • 定义:char *country[]={“A”,“E”,“A”,“C”,“j”};
#include <stdio.h>
int main()
{
    int i;
    char *country[]={"America","England","Australia","China","jsf"};
    for(i=0;i<5;i++)
    {
        printf("%s\n",country[i]);//输出每行的内容
    }

}

类型

  • 用数组指针的基类型-----指向数组的指针
int (*p)[5];
  • 用指针作数组的基类型------指针数组
    • 元素维指针类型的数组
    • 定义:数据类型 *数组名[数组长度]
char *p[5];
要明白什么是指针,必须先要弄清楚数据在内存中是如何存储的,又是如何被读取的。 如果在程序中定义了一个变量,在对程序进行编译时,系统就会为这个变量分配内存单元。编译系统根据程序中定义的变量类型分配一定长度的空间。内存的基本单元是字节,一字节有8位。每字节都有一个编号,这个编号就是“地址”,它相当于旅馆的房间号。在地址所标示的内存单元中存放的数据,就相当于在该旅馆房间中居住的旅客。 大家一定要弄清楚“内存单元的地址”和“内存单元的内容”这两个概念的区别,即“房间号”和“房间内所住客人”的区别。在程序中一般是通过变量名来对内存单元进行存取操作的。其实程序经过编译以后已经将变量名转换为变量的地址,对变量值的存取都是通过地址进行的。这种按变量地址存取变量的方式称为直接访问方式。 还有一种间接访问的方式,即变量中存放的是另一个变量的地址。也就是说,变量中存放的不是数据,而是数据的地址。就跟寻宝一样,可能你按藏宝图千辛万苦找到的宝藏不是金银珠宝,而是另一张藏宝图。按C语言的规定,可以在程序中定义整型变量、实型变量、字符型变量,也可以定义这样一种特殊的变量,它是存放地址的。 由于通过地址能找到所需的变量单元,所以可以说,地址“指向”该变量单元。如同一个房间号指向某一个房间一样,只要告诉房间号就能找到房间的位置。因此在C语言中,将地址形象地称为“指针”,意思就是通过它能找到以它为地址的内存单元。 所以,一个变量的地址就称为该变量的指针指针就是地址,而地址就是内存单元的编号。它是一个从零开始的、操作受限的非负整数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值