c语言指针

一、初级指针

1、什么是指针

指针是编程语言中的一个对象,利用地址,它的值直接指向存在电脑存储器中另一个地方的值。意思是通过它能找到以它为地址的内存单元。

指针是一个变量,存放内存单元的地址(编号)。

对应到代码:

int main(){
    int a = 10;//a占四个字节,&a指向四个字节中的第一个字节
    int * pa = &a;//将a的地址存放在pa变量中,pa就是一个指针变量
    *pa = 20;
    return 0;
}

 指针的大小在32位平台是4个字节,在64位平台是8个字节

2、指针和指针类型

1)指针类型的意义

所有类型的指针都为4个字节

1、指针类型决定了:指针解引用的权限有多大(能操作几个字节)

2、指针类型决定了:指针走一步能走多远(步长)

2)野指针

1、指针未初始化

int main(){
    int* p;//p是一个局部的指针变量,局部变量不初始化,默认为随机值
    *p = 20;//非法访问内存
    return 0;
}

2、指针越界访问

int main(){
    int arr[10] = {0};
    int* p = arr;
    int i = 0;
    for (i=0; i<= 10; i++){//指针越界
        *p = i;
        p++;
    }
}

3、指针指向的空间释放

解决:

        1)不知道p应该初始化为什么地址是,可以指向NULL

        2)小心指针越界

        3)指针指向空间释放及时置NULL

        4)指针使用之前检查有效性

3、指针运算

1)指针+-整数

#define N 5
float values[N];
float* vp;
//指针+-整数运算
for (vp = &values[0]; vp<&values[N]; ){
    *vp++ = 0;
}

2)指针-指针

int main(){
    int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    printf("%d\n", &arr[9] - &arr[0]);
    return 0;
}
//运行结果为9

指针-指针得到两个指针之间的元素个数

应用:求字符串长度

int my_strlen(char *s){
    char *p = s;
    while(*p != '\0')
        p++;
    return p-s;
}

4、指针与数组

int main(){
    int arr[10] = {0};
    int *p = arr;
    return 0;
}

其中:arr[2] 相当于*(arr+2)相当于*(p+2) 相当于p[2]

5、二级指针

int main(){
    int a = 10;
    int* pa = &a;
    //ppa为二级指针变量
    int* *ppa = &pa;
    return 0;
}

其中:**ppa == a

6、指针数组

指针数组仍然是数组,是存放指针的数组。

int main(){
    int arr[10] = {0};//整形数组
    char ch[5] = {0}; //字符数组

    //指针数组-存放指针的数组
    int* parr[10];//整形指针的数组
    return 0;
}

二、指针进阶

1、字符指针

 使用:

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

    //本质上是把“hello”这个字符串的首字符的地址存放在了ps当中
    char* ps = "hello";
    char arr[] = "hello"
    printf("%c\n", ps);//h
    printf("%s\n", ps);//hello
    printf("%s\n", arr);//hello
    return 0;   
}

经典题目

其中str3/4指向的是常量字符串

2、指针数组

int main(){
    int *arr[3]; //存放整形指针的数组
    char ch[5] = {0}; //字符数组

    int a[5] = {1, 2, 3, 4, 5};
    int b[5] = {2, 3, 4, 5, 6};
    int a[5] = {3, 4, 5, 6, 7};
    int *arr[3] = {a, b, c};
    int i = 0;
    for (i=0; i<3; i++){
        int j = 0;
        for (j = 0; j<5; j++){
            printf("%d ", *(arr[i] + j);//==arr[i][j]
        }
        printf("\n");
    }
    return 0; 
}

3、数组指针

是一种指针,是指向数组的指针

eg.: int (*prr2)[10] 该指针能够指向一个数组,数组10个元素,每个元素的类型为int

eg.: int (*prr3[10])[5] 该指针是一个存放数组指针的数组,该数组能够存放10个数组指针,每个数组指针能够指向一个数组。数组5个元素,每个元素是int类型

int main(){
    int a = 10;
    int *pa = &a;
    char ch = 'w';
    char *pc = &ch;

    int arr[10] = {1, 2, 3, 4, 5};
    int (*parr)[10] = &arr;//取出的是数组的地址
    //parr就是一个数组指针

    double* d[5];
    double* (*pd)[5] = &d;
    return 0;
}

4、数组传参与指针传参

void print1(int arr[3][5], int r, int c){
    int i = 0;
    int j = 0;
    for (i=0; i<r; i++){
        int j = 0;
        for (j = 0; j<c; j++){
            printf("%d ", arr[i][j]);
        }
        printf("\n");
    }
}
void print2(int (*p)[5], int r, int c){
    int i = 0;
    int j = 0;
    for (i=0; i<r; i++){
        int j = 0;
        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}};
    //print1(arr, 3, 5);
    print2(arr, 3, 5);
    return 0; 
}

1、一维数组传参

#include <stdio.h>
void test(int arr[]){}   //ok
void test(int arr[10]){} //ok
void test(int *arr){}    //ok
void test2(int *arr[20]) //ok
void test2(int **arr)    //ok
int main(){
    int arr[10] = {0};
    int *arr2[20] = {0};
    test(arr);
    test(arr2);
}

2、二维数组传参

#include <stdio.h>
void test(int arr[3][5]){}   //ok
void test(int arr[][]){}     //错误,可以不知道有多少行,但是必须知道一行有多少个元素
void test(int arr[][5]){}    //ok
void test2(int *arr){}       //错误
void test2(int* arr[5]){}    //错误
void test2(int (*arr)[5]){}  //ok
void test2(int **arr){}      //错误
int main(){
    int arr[3][5] = {0};
    test(arr);
}

3、一级指针传参

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

4、二级指针传参

void print(int **p2){
    **p2 = 20;
}
int main(){
    int a = 10;
    int *pa = &a;
    int **ppa = &pa;
    test(ppa);
    printf("%d\n", a);

    return 0;
}

5、函数指针

指向函数的指针,存放函数地址的指针

int Add(int a, int b){
    return a+b;
}
int main(){
    //pf为一个函数指针变量
    int(*pf)(int , int) = &Add;

    int ret = (*pf)(3, 5);
    //int ret = pf(3, 5);
    //int ret = Add(3, 5);//三种均可
    //int ret = *pf(3, 5);//错误!

    //printf("%p\n", &Add);
    //printf("%p\n", Add);//两个完全相同
    return 0;
}

6、函数指针数组

7、指向函数指针数组的指针

8、回调函数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Gretchen_Q

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值