C语言基础(指针篇)

指针定义

地址:内存中每一个单元格的编号(门牌号)

指针:地址,内存地址

指针变量:存储地址的变量

一级指针

定义格式

存储类型 数据类型 *指针变量名;

int *p;

int *:表示变量 p 存放的是一个 int 类型的地址

例: int *p; //定义指针变量p

        int a=10;

        int *p=&a; //p中存储的就是a的地址

访问值:*指针变量名 *p

修改值:*指针变量名=新值

指针操作符

&:取地址

*:取内容,取地址内容 // 后面往往跟着的是地址

int a = 10;

*&a == a; // &和*互为逆运算

&*a; // 错误,单目运算符,执行顺序是从右向左执行,*a 错误,a 是变量不是地址

初始化

  • 将普通变量赋给指针

        int a=20;

        int *p=&a; //定义时同时赋值

        int *p; //野指针 乱指向

        int *p=NULL; //指针指向空

        int b=10;

        p=&b; //先定义后赋值

  • 将数组的地址赋值给指针

        char str[]="hello";

        char *p=str;

  • 将指针变量的值交给另一个指针变量

        int a=20;

        int *p=&a;

        int *q=p;

指针运算

算数运算

++   --   +    -

int a[5] = {1, 2, 3, 4, 5};

int *p = a; // a++; ; 错误,a 是常量,不能为左值

p++; ++p; 等价于 p = p + 1; 指针向高地址方向移动一个数据单位

p+n:指针向高地址方向访问 n 个数据单位

p-n:指针向低地址方向访问 n 个数据单位

数据单位:指针的类型大小

q-p:两个地址之间相隔数据元素的个数

q 和 p 两者的数据类型相同,q 为高地址,p 为低地址

最好是在同一个数组下进行

关系运算

> >= < <= == !=

用来比较地址的高低

高地址大于低地址

数据类型要相同,在同一存储区域

在同一数组中比较才有意义

赋值运算

=  +=  -=

指针大小

sizeof(指针变量名); // 指针大小

32 位操作系统当中:4 字节

64 位操作系统当中:8 字节

指针修饰

const:常量化 read only //可以修饰变量、可以修饰指针

int const a = 10; // 变量a只读

int const *p; // *p 指针指向的内容不能修改,指针指向可以修改

int *const p; // p 指针的指向不能修改,指针指向的内容可以修改

const int *const p; // 指针的指向和指针的内容都不能修改

void:不能修饰变量,可以修饰指针

void *p; // 任意类型的指针

一般用在函数的参数以及返回值中,在使用时需要进行强制类型转换
强制类型转换:

格式:

(强转的数据类型)要强转的变量名

注意:强转仅在当前这一条语句生效,对其他语句无效

段错误

  • 野指针

指针变量没有赋值

指针置空之后 对空间赋值

堆空间free之后 指针没有及时置空

int *p;
int a;
p = &a;
scanf("%d", p);
printf("%d\n", *p);
  • 内存泄漏

内存空间溢出或者程序未释放

对非法空间操作

char s[] = "hello";
char *p = s;
scanf("%s", p);
printf("%s\n", p);

大小端

大端:在低地址存放高字节数据,在高地址存放低字节数据

小端:在低地址存放低字节数据,在高地址存放高字节数据

int 4字节

int a=0x12345678; 起始地址:0x100

0x100

0x101

0x102

0x103

大端

0x12

0x34

0x56

0x78

小端

0x78

0x56

0x34

0x12

二级指针

一级指针:存放变量的地址

二级指针:存放一级指针的地址

定义格式

存储类型 数据类型 **指针变量名

int a = 10;

int *p = &a;

int **q = &p;

访问 a 的值:

a **q *p

访问 a 的地址:

&a p *q

访问 p 的地址:

&p q

指针和数组

直接访问:按变量的地址存取变量的值(通过数组名访问)

间接访问:通过存放变量地址的变量去访问变量(通过指针访问)

指针和一维数组

int a[]={1,2,3};

int *p=a;

直接访问:

间接访问:

注意:a 和 p 本质上不同,a 是地址常量,p 是变量,a 不能执行++操作,但是 p 可以

访问数组元素 a[i]的值:

直接访问:a[i] *(a+i)

间接访问:p[i] *(p+i)

访问数组元素 a[i]的地址:

直接访问:&a[i] a+i

间接访问:&p[i] p+i

指针和二维数组

int a[2][2]={1,2,3,4};

int *p=a;

a:数组名,表示第一行的首地址

a+1:第二行的首地址在

a 前面*,表示将行地址降级为列地址

*a:第一行第一列的地址

*a+1:第一行第二列的地址

*(a+1):第二行第一列的地址

*(a+1)+1:第二行第二列的地址

直接访问:

访问数组元素的地址:

&a[i][j] *(a+i)+j a[i]+j

访问数组元素的值:

a[i][j] *(*(a+i)+j) *(a[i]+j)

数组指针

定义:本质上是指针,指向的是数组(又称行指针)

格式:存储类型 数据类型 (*指针变量名)[列数];

int a[2][3] = {1, 2, 3, 4, 5, 6};

int (*p)[3] = a;

p 可以代替 a 进行元素访问,但是本质不同

访问 a[i][j] 地址: *(p+i)+j p[i]+j

访问 a[i][j] 内容: *(*(p+i)+j) *(p[i]+j)

数组指针的大小: sizeof(p) = 8;

指针数组

定义:本质上是数组,里面存放的是指针

格式: 存储类型 数据类型 *数组名[元素个数];

  • 用于存放普通变量的地址

        int a = 10, b = 20, c = 30;

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

        访问 b 的地址: *(p+1) p[1]

        访问 b 的值: *(*(p+1)) *p[1]

  • 用于存放二维数组每一行第一列的地址

        int a[2][3] = {1, 2, 3, 4, 5, 6};

        int *p[2] = {a[0], a[1]};

        访问 a[1][2] 的地址: p[1]+2 *(p+1)+2

        访问 a[0][1] 的元素: *(p[0]+1) *(*(p+0)+1)

  • 用于存放字符串

        char *p[3] = {"hello","world","hq"};

        printf("%s\n",p[0]); //hello

        printf("%s\n",p[1]); //world

        printf("%s\n",*(p+2)); //hq

        printf("%c\n",*(*(p+1)+2)); //r

        printf("%c\n",p[2][1]); //q

  • 命令行参数

        int main(int argc, char const *argv[])

        {

                return 0;

        }

argv:就是一个指针数组,里面存放的是命令行传递的字符串

argc:表示 argv 指针数组里面存放的数据的个数,即命令行传递字符串的个数

 指针编程练习

示例一:编写一个程序实现功能:将字符串“Computer Science”赋值给一个字符数组
从第一个字母开始间隔的输出该字符串,用指针完成。结果:Cmue cec

#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
    char buf[] = "Computer Science";
    char *p = buf;
    // for (int i = 0; i < strlen(buf); i += 2)
    // {
    //     printf("%c", p[i]);
    // }
    while(p < buf+strlen(buf))  
    {
        printf("%c", *p);
        p += 2;
    }
    printf("\n");
    return 0;
}


示例二:用指针实现字符串倒置

#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
    char buf[]="hello";
    char *p = buf;
    char *q = p + strlen(buf) - 1;
    for (int i = 0; i < strlen(buf) / 2; i++)
    {
        char temp = *(p+i);
        *(p+i) = *(q-i);
        *(q-i) = temp;
    }
        printf("%s\n", buf);
}


示例三:循环输入一个五位数,判断它是不是回文数(指针完成)

#include <stdio.h>
int main(int argc, char const *argv[])
{
    int i;
    int *p=&i;
    while (1)
    {
        printf("input:\n");
        scanf("%d", &i);
        if (*p == 0)
        {
            break;
        }
        else if ((*p % 10)== (*p / 10000) && (*p % 100 / 10) == (*p / 1000 % 10))
        {
            printf("%d是回文数\n", i);
        }
        else
        {
            printf("%d不是回文数\n", i);
        }
    }
    return 0;
}


示例四:将字符串转换成整型数字输出。用指针实现
要求:字符串为0-9组成,输出数据为一个整型数
例:char s[10]="123";printf(“%d\n",num);//num=123;

#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
    char str[32] = "123456";
    int num=0;
    // scanf("%s", str);
    char *p = str;
    for (int i = 0; i < strlen(str); i++)
    {
        num = num * 10 + *(p + i) - 48;
    }
    printf("%d\n", num);
    return 0;
}


示例五:输入一个字符串,获取字符串中a字符首次出现的下标(用指针实现)

#include <stdio.h>
int main(int argc, char const *argv[])
{
    char str[32];
    char *s = str;
    int n=0;
    printf("请输入一个字符串:\n");
    scanf("%s", str);
    while(*s!='a')
    {
        s++;
        n++;
    }
    printf("%c %d",*s,n);
    putchar('\n');

    // char *p[3] = {"hello", "world", "ak"};
    // for (int i = 0; i < 3; i++)
    // {
    //     for (int j = 0; p[i][j] != '\0'; j++)
    //     {
    //         if (p[i][j] == 'a')
    //         {
    //             printf("%c [%d][%d]\n", *(*(p + i) + j), i, j);
    //             break;
    //         }
    //     }
    // }
   
    return 0;
}


示例六:已知字符数组a[10]和b[10]中元素的值递增有序,用指针实现将两个数组中元素按照递增顺序输出。如:char a[10]="acdgimno”; char b[10]="befhil”;--->"abcdefghilmno”

#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
    char a[10] = "acdgjmno";
    char b[10] = "befhil";
    char *p = a, *q = b;
    while (*p != '\0' && *q != '\0')
    {
        if (*p < *q)
        {
            printf("%c", *p);
            *p++;
        }
        else
        {
            printf("%c", *q);
            *q++;
        }
    }
    if (*p == '\0')
        printf("%s", q);
    else
        printf("%s", p);
        printf("\n");
    return 0;
}

示例七:用数组指针遍历二维数组

#include <stdio.h>
int main(int argc, char const *argv[])
{
    int i, j;
    int arr[2][3] = {1, 2, 3,4, 5, 6};
    int (*p)[3]=arr;
    for (i = 0; i < 2; i++)
    {
        for (j = 0; j < 3; j++)
        {
            printf("%d ",*(*(p+i)+j));
        }
        printf("\n");
    }
    return 0;
}

示例八:用指针数组遍历二维数组

#include <stdio.h>
int main(int argc, char const *argv[])
{
    int i, j;
    int arr[2][3] = {1, 2, 3, 4, 5, 6};
    int *p[2] = {arr[0],arr[1]};
    for (i = 0; i < 2; i++)
    {
        for (j = 0; j < 3; j++)
        {
            printf("%d ", p[i][j]);
        }
        printf("\n");
    }
    return 0;
}
  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值