搜索
bottom↓
回复: 29

c 语言,指针将一个字符串作为参数传入函数的问题

[复制链接]

出420入0汤圆

发表于 2022-7-21 14:09:50 | 显示全部楼层 |阅读模式
100汤圆
本帖最后由 asma 于 2022-7-21 14:40 编辑

void test(char *p)
{
        p = "1234";
}

int main()
{
        char *p = "abcd";
        test(p);
        printf("p: %s\r\n", p);
        return 0;
}

这儿 main () 调用 test (),传入指针 p,test () 里面将 p 指向了 “1234”,test () 结束,这样执行下一句打印 p 的字符串的时候,p 不是应该是指向 “1234” 了吗?

执行出来的结果却是 p:abcd。

为什么呢?一头雾水。哪位解释解释,或者有啥资料.各位给解释解释啊,不要代码

最佳答案

查看完整内容

C函数参数传的是变量【副本】,若想修变量【本身】,需要传指向变量的【指针】。 在变量本身是指针的情况下,原理类似:参数类型是 char*,因而传了指针数值的副本。 在函数里修改 p="1234" 只是修改了副本的数值,没有改到原指针; 但如果修改 p[0]='A' 这就是修改了指向的内容,打印是有效果的; 如果非要希望修改原始的指针数值,需要传入 char** ptr 这个类型,然后函数里 *ptr= "1234", 当然这么做也只是编译通过,还有更 ...

阿莫论坛20周年了!感谢大家的支持与爱护!!

如果天空是黑暗的,那就摸黑生存;
如果发出声音是危险的,那就保持沉默;
如果自觉无力发光,那就蜷伏于牆角。
但是,不要习惯了黑暗就为黑暗辩护;
也不要为自己的苟且而得意;
不要嘲讽那些比自己更勇敢的人。
我们可以卑微如尘土,但不可扭曲如蛆虫。

出200入2554汤圆

发表于 2022-7-21 14:09:51 | 显示全部楼层
本帖最后由 t3486784401 于 2022-7-21 15:15 编辑

C函数参数传的是变量【副本】,若想修变量【本身】,需要传指向变量的【指针】。
在变量本身是指针的情况下,原理类似:参数类型是 char*,因而传了指针数值的副本。

在函数里修改 p="1234" 只是修改了副本的数值,没有改到原指针;
但如果修改 p[0]='A' 这就是修改了指向的内容,打印是有效果的;

如果非要希望修改原始的指针数值,需要传入 char** ptr 这个类型,然后函数里 *ptr= "1234",
当然这么做也只是编译通过,还有更深的 BUG 等你:
"1234" 位于函数体内,当函数退出后是否能继续存在于内存中尚未可知,因而改完的 p 指针可能成为野指针

出0入475汤圆

发表于 2022-7-21 14:15:24 来自手机 | 显示全部楼层
没学过c语言的来款回答下,是不是test里面是临时变量,虽然你名字是用的p但是还是临时变量,那么甚至可能编译器都优化掉test里面的处理,除非你返回p。其实你不用形参,肯定就对了,

出0入8汤圆

发表于 2022-7-21 14:34:08 | 显示全部楼层
void test(char *p)
{
        *p = "1234";
}

int main()
{
        char *p = "abcd";
        test(&p);
        printf("p: %s\r\n", p);
        return 0;
}

出0入0汤圆

发表于 2022-7-21 15:04:12 来自手机 | 显示全部楼层
参数传递有两种形式,无论是哪一种,都是个拷贝……

出0入188汤圆

发表于 2022-7-21 15:08:18 | 显示全部楼层
外面的P指向地址A,然后把地址A作为形参传递给里面的指针P,这个时候,里面的指针P指向地址A,然后把地址B赋值给了里面的P,这时里面的指针P指向了地址B,和外面的针指P没有半毛钱关系,函数的传递是形参

出0入188汤圆

发表于 2022-7-21 15:11:17 | 显示全部楼层
简单来说,函数的参数传递,只能传递数值,也就是只能把外面指针指向的地址值传递给了里面的指针,而函数里面,只是改变了指针指向的地址,并没有改变原针指指向地址里面的值

出0入22汤圆

发表于 2022-7-21 15:26:08 | 显示全部楼层
你想改变一个指针变量,就要传入这个指针变量的地址,而不是指针本身。所以要传入的是&p,类型是char**(指针的指针)。

出0入33汤圆

发表于 2022-7-21 15:34:21 来自手机 | 显示全部楼层
一句话:你需要一个指向指针的指针

出0入18汤圆

发表于 2022-7-21 15:51:32 | 显示全部楼层
t3486784401 发表于 2022-7-21 15:12
C函数参数传的是变量【副本】,若想修变量【本身】,需要传指向变量的【指针】。
在变量本身是指针的情况下 ...
(引用自7楼)

大神精通C,厉害

出0入0汤圆

发表于 2022-7-21 16:06:40 | 显示全部楼层
t3486784401 发表于 2022-7-21 15:12
C函数参数传的是变量【副本】,若想修变量【本身】,需要传指向变量的【指针】。
在变量本身是指针的情况下 ...
(引用自7楼)

"1234" 位于函数体内,当函数退出后是否能继续存在于内存中尚未可知,因而改完的 p 指针可能成为野指针
这个"1234"在退出函数后,到底是否一定会丢失呢?
我不确定,不知道是否有明确的答案?望指教!

出200入2554汤圆

发表于 2022-7-21 16:21:56 | 显示全部楼层
擦鞋匠 发表于 2022-7-21 16:06
"1234" 位于函数体内,当函数退出后是否能继续存在于内存中尚未可知,因而改完的 p 指针可能成为野指针
...
(引用自11楼)

这个与编译器有关,大多数编译器倾向于把 "1234" 搞成全局的,即 main( ) 执行的全过程都存在。
例如单片机环境下,常量字串大多直接放在 RAM/ROM 固定区域,不移动不销毁,这样开销反而最小。

所以大多数 C 环境下,这个 "1234" 并不销毁,输出其地址也不会野指针。

高级语言里,输出局部非静态变量、类实例的地址,随着其析构销毁,常见结果就是找不到对象:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2022-7-21 16:26:29 | 显示全部楼层
这里的test(p)形参是值传递不是地址传递,我这里给你简单验证了下,看执行结果的地址就明白了:
#include <stdio.h>

void test(char *p)
{
                printf("test &p addr=%p \r\n",&p);
               p = "1234";
}

int main()
{
        char *p = "abcd";
                printf("main &p addr=%p \r\n",&p);
        test(p);
        printf("p: %s\r\n", p);
        return 0;
}


执行结果:
main &p addr=0x7ffc38455838
test &p addr=0x7ffc38455818
p: abcd

出1330入193汤圆

发表于 2022-7-21 16:51:24 | 显示全部楼层
vtte 发表于 2022-7-21 15:34
一句话:你需要一个指向指针的指针
(引用自9楼)

函数指针  指针函数     形参带结构体指针

出0入0汤圆

发表于 2022-7-21 17:30:27 | 显示全部楼层
t3486784401 发表于 2022-7-21 16:21
这个与编译器有关,大多数编译器倾向于把 "1234" 搞成全局的,即 main( ) 执行的全过程都存在。
例如单片 ...
(引用自12楼)

感谢阁下指教!

出0入0汤圆

发表于 2022-7-21 17:37:35 | 显示全部楼层
可以把常量放在函数体外;
char *str="1234";
函数体内指针,指向某个位置。相当于指针重定位。应该是可以的。

出0入0汤圆

发表于 2022-7-21 17:38:40 | 显示全部楼层
p本身而言只是个形参,不管你怎么修改p的值,退出函数p还是会回复原来的值。你只有修改p指向的值才会有效果。具体而言修改p=xx没有用,*p=xx,p[0]=xx都是有效果。

出0入0汤圆

发表于 2022-7-21 17:49:36 | 显示全部楼层
顺便学习下。

出0入18汤圆

发表于 2022-7-21 18:00:40 来自手机 | 显示全部楼层
我怀疑楼主以为*p=“1234”,是把1234写入p指向的地址了

出0入8汤圆

发表于 2022-7-22 08:29:08 | 显示全部楼层
这个问题很多人迷糊

出0入0汤圆

发表于 2022-7-22 08:40:42 | 显示全部楼层
要传指针地址,函数参数应是二重指针

出15入178汤圆

发表于 2022-7-22 10:36:49 | 显示全部楼层
  1. void test(char *(*p))
  2. {
  3.     *p = "1234";
  4. }

  5. int main()
  6. {
  7.     char *p = "abcd";
  8.     test(&p);
  9.     printf("p: %s\r\n", p);
  10.     return 0;
  11. }
复制代码

出0入8汤圆

发表于 2022-7-22 11:20:00 | 显示全部楼层
t3486784401 发表于 2022-7-21 15:12
C函数参数传的是变量【副本】,若想修变量【本身】,需要传指向变量的【指针】。
在变量本身是指针的情况下 ...
(引用自7楼)

请教大神,这里指针*v为什么又可以改变指向的值?谢谢

static uint8_t get_voltage(int16_t *v,  uint8_t channel)
{
        struct
        {
                int16_t coldVal;
                float coldTemp;
                float coldVolt;
                int16_t hotVal;
                float hotVolt;/*uV*/
                float volt;
                //float temp;/*℃*/
        }t;

        if (!read32bit(&t.coldVal, &t.hotVal, channel))/*读传感器*/
        {       
                *v =(int16)t.volt;
        }
        else
                return 1;/*读失败*/
        return 0;
}

出200入2554汤圆

发表于 2022-7-22 11:23:42 | 显示全部楼层
rube 发表于 2022-7-22 11:20
请教大神,这里指针*v为什么又可以改变指向的值?谢谢

static uint8_t get_voltage(int16_t *v,  uint8_ ...
(引用自23楼)

改变的是 v 指向的值,而不是变量 v 自身,这没毛病啊

出0入71汤圆

发表于 2022-7-22 12:01:42 | 显示全部楼层
本帖最后由 dellric 于 2022-7-22 12:04 编辑

void test(char *p) 这个里面的 指针(就是一个地址数值)是存储在栈上分配的内存里面,把“1234”的地址送给p,只是修改了栈上的这个地址数据,在test返回后,栈指针恢复到调用程序main上,这个地址数据也就无效了(或无关了),不会在main函数里面出现。所以,在test里面对p赋值,只修改了test栈上内容,不会影响main函数里面的p指针。

栈内存:
(1).  char * p         main函数里面分配的地址指针数据 p
(2).  main.test()     函数调用test的地址位置
(3).  char * p         test函数里面分配的地址指针数据 p

调用test()前,栈内只有(1), 调用test()后,系统把返回地址(2)压栈,再把栈指针减(或加)一个指针大小用于保存 test函数内的 p指针(3),test调用完毕后,栈指针会加(或减)一个指针内存大小,扔掉栈上分配的局部变量控件,然后栈指针指向返回地址(2),系统根据栈内存储的调用返回地址(2),回到main函数中调用test()函数的下一条指令位置继续执行后继代码。

从上可知,test函数内部的p指针(3),只是一个局部变量,再test函数返回的时候,就被忽略掉了,对他赋的任何值都是没有后继意义了。

出0入217汤圆

发表于 2022-7-23 14:24:49 | 显示全部楼层
如果这么写:
void test(char p)
{
        p = '1';
}

int main()
{
        char p = 'a';
        test(p);
        //现在p是什么?LZ应该是知道的吧
       //要修改p的值,必须传递p的指针
       //如果p本身就是指针呢,就传递指针的指针
        return 0;
}

出0入4汤圆

发表于 2022-7-23 15:39:00 来自手机 | 显示全部楼层
还是老老实实的声明为数组,然后取地址靠谱点,也好理解。

出0入0汤圆

发表于 2022-7-23 19:59:20 | 显示全部楼层
去掉指针符号*就好理解了

void test(char p)
{
        p = 1234;
}

int main()
{
        char p = 4321;
        test(p);
        printf("p: %d\r\n", p);
        return 0;
}

出0入4汤圆

发表于 2022-7-25 09:06:56 | 显示全部楼层
指针的指针!!
void test(char **p)
{
        *p = "1234";
}

int main()
{
        char *p = "abcd";
        test(&p);
        printf("p: %s\r\n", p);
        return 0;
}

出420入0汤圆

 楼主| 发表于 2022-7-26 11:08:21 | 显示全部楼层
本帖最后由 asma 于 2022-7-26 11:11 编辑
t3486784401 发表于 2022-7-21 14:09
C函数参数传的是变量【副本】,若想修变量【本身】,需要传指向变量的【指针】。
在变量本身是指针的情况下 ...
(引用自7楼)


讲的通俗易懂,适合我这初学者。非常感谢
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-9-27 07:13

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表