函数与指针参数——关于两道题目的个人理解

题目1,下面的代码的输出结果是什么

 1 #include<stdio.h>
 2
 3 void get(char *p)
 4 {
 5     p="hello!";
 6 }
 7
 8 int main(int argc, char const *argv[])
 9 {
10     char *str=NULL;
11     str = get();
12
13     printf("%s\n",str);
14
15     return 0;
16 }

读者也可以自己思考一下答案是多少,当时我不假思索地写了:hello!

结果答案却是输出乱码,测试了一下指针str还是指向NULL,这是为什么呢?

原来我在这里面犯了个常见的关于实参和形参的低级错误。

先看下面这段经典的学校教函数时用指针作为参数的swap代码:

1 void swap(int *p,int *q)//交换2个整数
2 {
3     int temp;
4     temp=*p;
5     *p=*q;
6     *q=*p;
7 }

这段函数在这里是不用返回值的,很多书都拿这段代码来作为函数中指针间接修改变量的例子。

最近在系统巩固C语言,所以这段代码块看的多了,导致一看到指针变量作为函数的参数传递进去,就傻傻地默认了拥有指针参数的函数一旦有指针传递进去,那么该传递进去的指针在函数里面的操作会影响到该指针。其实这样的是的!其实仔细回想指针的知识,在这段代码中,其实是利用p、q两个指针指向的地址去修改对应的变量,即用*运算符去对象后去修改的对应的数据的。

好比如 爸爸给了小明(swap()这个函数) p和q这2把钥匙让他去把2个对应房间的家具互调,最后小明不用把房间的钥匙给回爸爸,房间的家具实际上已经互调了。

回头看一下上面的题目

1 void get(char *p)
2 {
3      p="hello!";
4 }

这里说白了p就是个参数,既然作为参数传递进去,你想到得到其结果,就应该把他return回来!否则一旦这个函数调用完毕,系统就会释放他,p也就没有了,就是个临时工。

运行这个函数就好比如,小明去钥匙店(函数get(char *p))配了一把房间(也就是常量"hello!")的钥匙p,然后钥匙都没拿就走了,老板要这个钥匙也没用,就把它扔了,也就是运行完get()之后,p就没了,被释放了,根本没把这钥匙交给任何人!函数的调用者小明也没有得到任何东西,白跑一趟。

所以程序应该修改为:

1 char *get(char *p)
2 {
3     p="hello";
4     return p;
5 }

这样才能把在get(char *p)里面配的钥匙p给return出去,才能交给函数的调用者(来配钥匙的人)。



题目2:求下面的函数输出:

 1 #include<stdio.h>
 2
 3 char *get(void)
 4 {
 5     char p[]="hello!";
 6     return p;
 7 }
 8
 9 int main(int argc, char const *argv[])
10 {
11     char *str=NULL;
12     str = get();
13
14     printf("%s\n",str);
15
16     return 0;
17 }

乍一看好像答案又是:hello!

其实是错的,答案还是乱码!

相信很多人学习指针和数组的时候,在脑袋里就被这样一句话给框住——“数组名就是指向其数组首元素的指针常量”

比如char a[]=“abc”;

那么printf("%c",a);

输出就是:a

答案也确实是如此,于是很多人就把上面的子函数char *get(void)的功能以为是:

【返回指向字符串常量"hello!"首地址的一个字符指针】

其实这样的理解是错误的,先来看看调用这个函数

str=get();

这一过程系统是怎么处理的。

1、声明一个字符数组p[],并且系统把存储在静态储存区的字符串常量"hello!"复制到p指向的连续内存空间上!

2、返回指针p的地址

3、(重要)这是个子函数,所以系统自然会释放掉函数中的临时变量char p[]

请看好第3步,p的地址虽然给了str,但是p指向的那片内存在get()运行后就释放了,所以复制过来的"hello!"也就没了!

所以当主程序再去printf指针str指向的区域,出来的就不是"hello!",而是乱码,因为子函数中临时的"hello!"已经释放掉了!

所以程序可以修改如下,输出结果就是正确的:

1 char *get(void)
2 {
3     char *p="hello";
4     return p;
5 }

到这里有读者就会问了,不都是个指针p指向字符串"hello!"吗?为什么结果不一样呢?

下面来看一下上面修改的程序的运行过程:

可以看出,当定义为指针类型时,p存放"hello!"在静态存储区中的地址,所以p给了str后,printf("%s",str)就能打印出hello!

透过现象看本质

1、当定义为char p[]="hello!";

 的时候,p就固定下来,是一个指针常量!指向的内存放着拷贝过来的"hello!"     (‘h‘,‘e‘,‘l‘,‘l‘,‘o‘,‘!‘,‘\0‘)

2、当定义为char *p="hello!"的时候,则p是直接指向静态存储区的"hello!"

本文为原创,转载请注明出处。



函数与指针参数——关于两道题目的个人理解

时间: 2024-08-11 09:48:43

函数与指针参数——关于两道题目的个人理解的相关文章

编程题:指向函数的指针,求两个数中较大的数。

#include<stdio.h> int max(x,y) { int z; if(x>y)  z=x; else  z=y; return z; } void main() { int a,b,c; int (*p)(); p=max; scanf("%d,%d",&a,&b); c=(*p)(a,b); printf("%d,%d,max is %d\n",a,b,c); } 编程题:指向函数的指针,求两个数中较大的数.,布布

C语言:通过函数指针来完成两个数的加减乘除(函数指针当做参数使用)

// //  main.c //  Function_pointer // //  Created by mac on 15/8/2. //  Copyright (c) 2015年 bjsxt. All rights reserved. //  要求:将函数指针做参数来求两个整数的和.差.积.商. //知识点:函数指针就是一个指向函数的指针,通过指针指向要调用的函数来完成操作.其实,这个指针就是指向函数的入口地址. //切记:要被调用的函数必须和函数指针的声明的一样(包括:返回值类型.参数个数

以指针和引用两种参数实现删除单链表L中所有值为X的结点的函数

下面是单链表的数据结构 typedef struct LNode{ ElemType data; struct LNode *next; }LNode,*Linklist; 1.以指针参数实现 void delete_x_1(LNode *head,ElemType x){//head为单链表头结点,删除结点的值为x LNode *l = head; LNode *p = head->next; while(p != null){ if(p->data == x){ l->next =

基类中定义的虚函数在派生类中重新定义时,其函数原型,包括返回类型、函数名、参数个数、参数类型及参数的先后顺序,都必须与基类中的原型完全相同 but------&gt; 可以返回派生类对象的引用或指针

您查询的关键词是:c++primer习题15.25 以下是该网页在北京时间 2016年07月15日 02:57:08 的快照: 如果打开速度慢,可以尝试快速版:如果想更新或删除快照,可以投诉快照. 百度和网页 http://bbs.csdn.net/topics/380238133 的作者无关,不对其内容负责.百度快照谨为网络故障时之索引,不代表被搜索网站的即时页面. 首页 精选版块 移动开发 iOS Android Qt WP 云计算 IaaS Pass/SaaS 分布式计算/Hadoop J

C语言:通过函数指针来完成两个数的加减乘除

// //  main.c //  Function_pointer // //  Created by mac on 15/8/2. //  Copyright (c) 2015年 bjsxt. All rights reserved. //  要求:通过函数指针求两个整数的和.差.积.商. //知识点:函数指针就是一个指向函数的指针,通过指针指向要调用的函数来完成操作. //切记:要被调用的函数必须和函数指针的声明的一样(包括:返回值类型.参数个数和类型) #include <stdio.h

C++函数的传入参数是指针的指针(**)的详解

要修改变量的值,需要使用变量类型的指针作为参数或者变量的引用.如果变量是一般类型的变量,例如int,则需要使用int 类型的指针类型int *作为参数或者int的引用类型int&.但是如果变量类型是指针类型,例如char*,那么需要使用该类型的指针,即指向指针的指针类型 char* *,或者该类型的引用类型char*&. 首先要清楚  不管是指针还是值传入函数后都会创建一个副本,函数结束后值内容不能传出来是因为值的副本,而传入的值并没被修改,指针能传出来是因为我们修改的是指针指向的内容而不

指针实现两数交换和指向函数的指针

指针就是地址,而指针变量就是存储地址的变量. 1.指针与函数 利用指针解决: C语言中函数的参数采用"单向传递",故第一个程序中改变形参不会改变实参,而在第二个程序中,使用指针变量作为参数,改变指针变量所指向的值,函数调用结束后,变量值被保留下来. 2.指向函数的指针的应用

二级指针和函数参数——指针参数是如何传递内存的?

1:如果函数的参数是一个指针,不要指望用该指针去申请动态内存.Test 函数的语句 GetMemory(str, 200)并没有使 str 获得期望的内存,str 依旧是 NULL,为什么? void GetMemory(char *p, int num) { p = (char *)malloc(sizeof(char) * num); } void Test(void) { char *str = NULL; GetMemory(str, 100); // str 仍然为 NULL strc

深度探索C语言函数可变长参数

通常我们使用的C函数的参数个数都是固定的,但也有不固定的.比如printf()与scanf().如何自己动手实现一个可变参数函数,这个还是有点技巧的. 我们最常用的就是定义一个宏,使用printf或者printk,如下 #define wwlogk(fmt, args...) printk(fmt, ## args) 现在我们自己动手实现一个可变参数的函数,后面分析原理.首先看一个例子: #include <stdio.h> #include <stdarg.h> int Sum(