要么改变世界,要么适应世界

C语言的指针

2020-06-29 08:56:00
297
目录

指针作为参数传递

C语言中,当指针作为函数参数进行传递时,实际上形参和实参指向的是同一个地方,例如:

/*
 * @Author: YaleXin
 * @Date: 2020-06-19 18:02:53
 * @LastEditTime: 2020-06-29 08:59:40
 * @LastEditors: YaleXin
 * @Description:
 * @FilePath: \my_c_workspace\some_test\pointTest-copy.c
 * @祈祷不出现BUG
 */
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
void test(int *p1) { printf("=== test p1 = %p ====\n", p1); }
int main() {
    int *p;
    printf("=== main p = %p ====\n", p);
    test(p);
    return 0;
}

输出的是:

=== main p = 0000000000000010 ====
=== test p1 = 0000000000000010 ====

可见二者的地址是相同的。

所以形参对其指向的内存区域进行修改,也会影响到实参指向的内存区域,因为二者指向的区域是同一个位置,例如:

/*
 * @Author: YaleXin
 * @Date: 2020-06-19 18:02:53
 * @LastEditTime: 2020-06-29 09:08:30
 * @LastEditors: YaleXin
 * @Description:
 * @FilePath: \my_c_workspace\some_test\pointTest-copy.c
 * @祈祷不出现BUG
 */
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
void test(int *p1) { *p1 = 2; }
int main() {
    int a = 1;
    int *p = &a;
    printf("before a = %d\n", a);
    test(p);
    printf("after a = %d\n", a);
    return 0;
}

输出的是:

before a = 1
after a = 2

但是,我们再来看一个例子:

/*
 * @Author: YaleXin
 * @Date: 2020-06-19 18:02:53
 * @LastEditTime: 2020-06-29 09:16:55
 * @LastEditors: YaleXin
 * @Description:
 * @FilePath: \my_c_workspace\some_test\pointTest-copy.c
 * @祈祷不出现BUG
 */
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
void test(char *p1) { p1 = "modified"; }
int main() {
    char *p = NULL;
    test(p);
    printf("after p = %s\n", p);
    return 0;
}

很容易让人以为输出的是

after p = modified

但是实际上输出的是

after p = (null)

下图给出这个过程中,指针的变化:

1

实际上是因为形参指向的区域已经与实参指向的不一致。

但是假如有在被调函数改变实参的地址的需求怎么办?

两种方法:

  1. 被调函数返回指针:

    #include <malloc.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <malloc.h>
    #include <stdio.h>
    #include <stdlib.h>
    char *test(char *p1) { p1 = "modified"; }
    int main() {
        char *p = NULL;
        p = test(p);
        printf("after p = %s\n", p);
        return 0;
    }
    

    但是使用该方法的时候,不推荐返回局部指针,返回局部指针很容易出现错误,详见这篇文章

    下面的例子就是存在问题:

    #include <malloc.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <malloc.h>
    #include <stdio.h>
    #include <stdlib.h>
    char *test(char *p1) {
        p1 = "modified";
        char str[20] = "";
        sprintf(str, "yalexin %s", p1);
        printf("str = %s\n",str);
        return str;
    }
    int main(void) {
        char *p = NULL;
        p = test(p);
        printf("after p = %s\n", p);
        return 0;
    }
    
    

    输出的是:

    str = yalexin modified
    after p = (null)
    
    
  2. 使用二级指针:

    #include <malloc.h>
    #include <stdio.h>
    #include <stdlib.h>
    char test(char **p1) { *p1 = "modified"; }
    int main(void) {
        char *p = NULL;
        printf("调用函数之前p的地址是 %p\n", p);
        test(&p);
        printf("调用函数之后p的地址是 %p\n", p);
        printf("after p = %s\n", p);
        return 0;
    }
    
    

    输出:

    调用函数之前p的地址是 0000000000000000
    调用函数之后p的地址是 0000000000404000
    after p = modified
    
    

注意事项

  1. 当指针指向的是一个变量,例如*int* *p = &a;,是不能使用free(p)进行释放资源, free() 只是针对使用了 malloc()realloc()函数进行申请的内存进行释放。
  2. 使用free()后,相应的指针就会变为“野指针”,如果对野指针进行引用,会造成不可预期的后果,所以一般使用free(p)后,一般紧接着p = NULL
历史评论
开始评论