C语言- 指针用法

2021-12-11  本文已影响0人  我阿郑

如何表示地址?

地址是整数,是否可以用int?
理论上可以,但是为了强调它是个内存地址,提出一些新的类型:

char* :表示一个char类型变量的地址
short* :表示一个short类型变量的地址
int* :表示一个int类型变量的地址
float* :表示一个float类型变量的地址
double* :表示一个double类型变量的地址
unsigned char* :表示一个unsigned char类型变量的地址
XXX* : 表示XXX类型变量的地址

上面的指针都是基本数据类型的指针
基本类型指针就是指:存放基本数据类型地址的指针

int *p;
int i = 3;
p = &i;

int j;
j = *p;

关于指针

int a = 10;
int* pa = &a; 
double* pd = pa; // Error ❌ 左侧double* ,右侧int* , 不能互相赋值

char a = 78;
float* p = &a; // Error ❌ 左侧float* ,右侧cahr* , 不能互相赋值

以下几种方式均可以,没有区别, 看个人习惯

int* p;
int * p;
int *p;

星号操作:按地址访问

有一个指针变量p, 则p用于访问p指向的变量*(p指向的内存)。

int a = 0x123;
int *p = &a; // p指向a所在的内存
*p += 2;

int b = *p;  // 取得p指向内存的值
int c = *p + 2;

指针作为函数的参数

可以把指针作为函数的参数

void test(int *p) {
    // 能把指针干什么呢?
    // 使用星号操作*p,来读写内存
    *p = 10;
}

int main() {
    int a = 0;
    test(&a);
    print("a=%d",a); // 打印10
}

使用指针作为参数,可以实现两种功能:

例: 交换两个变量的值
void swap(int* a, int* b)
{
    int t = *a;
    *a = *b;
    *b = t;
}
int main()
{
    int a=10, b=11;
    swap(&a, &b);
    return 0;
}

传递数组作为参数

之前说过数组名,实质就是指针类型,传递数组,就是传递指针

int test(int *p, int length) {
    int sum = 0;
    for(int i=0; i<length; i++) {
        sum += p[i];
    }
    return sum;
}

int main() {
    int arr[] = {1, 2, 3, 4};
    int ret;
    
    ret = test(arr,4); // 从arr[0] 到 arr[3] 结果sum=10
    ret = test(arr,3); // 从arr[0] 到 arr[2] 结果sum=6
    ret = test(arr + 1,3); // 从arr[1] 到 arr[3] 结果sum=9
    
}

❤️ 对于test函数来说,不关心传进来的是不是数组;在它眼里,它只是接收到一个内存地址而已

int test(int *p, int length)
和
int test(int p[], int length)

传指针有什么作用?

把一个指针传给函数,有什么作用?

如何安全的使用指针 ?

指针不可乱用,安全的使用指针,需要对指针有足够清晰的认识。
在使用指针之前,一定要弄清楚两个问题:

指针指向了哪儿?

指向0的情况:(空指针

int* p = 0; // 空指针

空指针

值为0的指针,称为空指针

int* p = 0;

当指针为空时,不能使用星号操作。
int* p = 0;
printf(“%d \n”, *p); // 不能这么干❌

但空指针是程序员可以接受的一种情况,只需加一个if判断就能解决!
if(p) {
    printf(“%d \n”, *p);
} 

空指针:应用

某些参数可以省,当不想传入时就传一个空指针

void max_min(const int* arr, int len,
                int* pmax, int* pmin)
{
    ...
    if(pmax) *pmax = _max;
    if(pmin) *pin = _min;
}
// 调用时
int _max;
// 表示只需要得到最大值
max_min(arr,4, &_max, 0); 

危险的情况

int* p;
printf("%d", *p); // 立即crash

这个指针指向哪了? 当一个指针未赋值时,其值为随机值,此时指向了一个随机的内存地址,称为“野指针”

安全使用指针

1-杜绝野指针

一个好习惯:初始化为空指针 : int * p = 0;

考虑:为什么传递一个空指针是允许的?而传一个野指针是不允许的? (空指针也会崩溃)

int *  p = 0;
printf(“ %d  \n”, *p); // 空指针也会崩溃 ❌

传递空指针:函数内部是有办法处理,判断一下就行。
传递野指针:函数内无法判断出来你是个野指针!!

void test(int* p)
{
  // 在使用指针前判断
    if( p != 0)
    {
         printf(“%d \n”, *p);
    }
}

2-严防数组越界

当指针指向数组时,要注意不要越界访问

int arr[4];
int* p = arr;

p += 4;
*p = 12; // 已经越界!但不容易察觉!

3-变量是否已经失效?

如果指向的目标的生命期已经终结(失效),则该指针也失效

int main()
{
    int* p = 0;
    if(1)
    {
        int a = 10; // a生效
        p = &a; // p指向a
    } // a已失效

    *p = 11; // p指向了一个无效的位置⚠️
    return 0;
}

所以,指向全局变量的指针,安全性相对较高。因为它的生命期是永恒的,这一块内存总是有效。

上一篇 下一篇

猜你喜欢

热点阅读