指针传参和接收返回值对指针的影响

1. 指针传参和接收返回值对指针的影响

1.1 题1

#include<stdio.h>

//注意堆区和栈区中变量的区别!!!!!
void test(int* str){
    int a = 10;
    str = &a;
}

int main()
{
    int b = 20;
    int *p2 = &b;
    test(p2);
    printf("p2的%d",*p2);
    
}

在 test 函数内部,你定义了一个局部变量 a,并尝试将指针 str 指向 a 的地址。这是有效的,但请注意,这不会影响 main 函数中的 p2,因为 str 变量只是 test 函数的局部变量,它的改变不会影响 p2。

test 函数返回,a 的生命周期结束,它的内存被释放。此时,str 不再指向有效的内存地址。

在 main 函数中,你尝试访问 *p2,这实际上是访问 b 的值,因为 p2 一直指向 b 的地址。你无法访问 a 的值,因为它的内存已经被释放。

如果你想在 main 函数中访问 a 的值,你需要更改你的代码逻辑,例如,将 a 声明为全局变量,或者通过动态内存分配来管理它的生命周期。

1.2 题2

#include<stdio.h>
#include<stdlib.h>

//注意堆区和栈区中变量的区别!!!!!

void test2(int* str){
    int* c = (int*)malloc(sizeof(int));
    *c = 30;
    str = c;
}

int main()
{
    int b = 20;
    int* p2 = &b; 
    test2(p2);
    printf("p2的%d",*p2);
}

注意指针的传递

对于题二的更改要么设置返回值,要么传地址

1.3 题3

#include<stdio.h>

//注意堆区和栈区中变量的区别!!!!!

int* test2(){
    int* c = (int*)malloc(sizeof(int));
    *c = 30;
    return c;
}

int main()
{
    int b = 20;
    int* p2 = &b; 
    p2 = test2();
    printf("p2的%d",*p2);
    free(p2);
}

代码正确

动态分配的内存再堆上不会自动释放

1.4 题4

#include<stdio.h>
#include<stdlib.h>

//注意堆区和栈区中变量的区别!!!!!
void test(int** str){
    
    //不安全的
    // int a = 10;
    // *str = &a;

    //安全的写法
    int* a = (int*)malloc(sizeof(int));
    *a=10;
    *str = a;

}


int main()
{
    int b = 20;
    int *p2 = &b;
    test(&p2);
    printf("p2的%d",*p2);
}

存在悬空指针问题,不安全,避免这种写法

使用第二种写法

1.5 题5

#include<stdio.h>

//注意堆区和栈区中变量的区别!!!!!

int* test2(){
    int c = 30;
    int* str = &c;
    return str;
}

int main()
{
    int b = 20;
    int* p2 = &b; 
    p2 = test2();
    printf("p2的%d",*p2);
}

当你在一个函数中创建一个局部变量(比如 int c = 30;),这个变量通常会分配在栈内存中。当函数执行完毕,栈上的局部变量会被销毁,这是栈的典型行为。这意味着局部变量 c 的内存将在 test2 函数结束时被释放,不再可访问。

这种情况可以分为两种

1. c被保存到寄存器且p2拿到的也是寄存器的地址

然而,编译器可以进行优化,有时候它会将局部变量 c 的值保存在寄存器中,而不是栈上。

因此它可以将其保存在寄存器中以提高代码执行的效率。这个过程称为寄存器分配优化。

如果 c 的值被保存在寄存器中,那么返回 &c(c 的地址)给 main 函数实际上是返回寄存器中的地址,而不是栈上的地址。所以可以访问到c

2. c是被销毁了,但是p2拿到了地址,可能是个悬空指针,但 p2 仍然包含了之前的地址。尝试访问 c 的值可能会导致未定义的行为,因为它指向的内存可能已经被其他数据覆盖。但是这期间由于某种原因,被销毁的变量的内存内容仍然可以保留一段时间,c这个地址还没有被覆盖导致你依然可以访问到

但是,这种行为是不可靠的,因为它依赖于编译器和编译器优化的具体实现。不同的编译器和编译选项可能会导致不同的结果。因此,为了编写可移植且健壮的代码,最好避免返回指向局部变量的指针,因为这可能导致未定义的行为。

由于这两种情况都可能发生,代码的行为是不确定的。这就是为什么悬挂指针是一个不安全的编程实践,因为它依赖于编译器的实现细节和优化。你应该避免使用悬挂指针,以确保代码的可靠性和可移植性。如果你需要跨函数访问局部变量的值,最好使用全局变量、堆内存分配或其他方法来确保数据的有效性。

1.6 题6

#include<stdio.h>


void test(int* str){
    int a = 10;
    str = &a;
}

int main()
{
    int* p1=NULL;
    test(p1);
    printf("p1的%d",*p1);
}

虽然p1是指针,指向了NULL,也传递了 ,但是函数的str只是p1的拷贝临时的,虽然和p1一样指向NULL,但是他要改变指向并不会影响p1

2. 计算字符串大小的坑

void test(char arr[]){
    printf("%d\n",sizeof(arr));//这里计算的是指针大小  8
}

int main()
{

//    char arr[] = "abcd";
   test("abcde");
    return 0;
}

计算的是指针大小

void test(char arr[]){
printf("%d\n",sizeof(arr));
}

int main()
{

char arr[] = "abcd";
test(arr);
return 0;
}

在C语言中,数组作为函数参数传递时,它会被转换成指针类型。因此,在函数test中,sizeof(arr)实际上返回的是指针的大小,而不是数组arr的大小。所以即使arr在main函数中是一个字符数组,它在test函数中被视为指针。因此,在test函数中,sizeof(arr)返回的是指针的大小,而不是数组的大小。

在这种情况下,sizeof(arr)返回的大小通常是指针大小,即4或8字节(具体取决于你的系统,32位系统一般是4字节,64位系统一般是8字节)。

如果你想在test函数中获得数组的大小,你可以传递数组的长度作为参数,或者使用C语言中的一些特殊技巧,比如使用一个标记来表示数组的结尾。

  • 29
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值