详解C语言函数返回值解析

详解C语言函数返回值解析

程序一:

int main()

{

  int *p;

  int i;

  int*fun(void);

  p=fun();

  for(i=0;i<3;i++)

  {

    printf("%d\n",*p);

    p++;  

  }

  return 0;

};

int* fun(void)

{

  static int str[]={1,2,3,4,5};

   int*q=str;

  return q;

}

//不能正确返回

虽然str是在动态变量区,而该动态变量是局部的,函数结束时不保留的。

程序二:

int main()

{

  char *p;

  char*fun(void);

  p=fun();

  printf("%s\n",p);

  return 0;

};

char * fun(void)

{

  char *str="hello";

  return str;

}

//可以正确返回

但是,字符串"hello"不是变量,而是一个常量,编译程序在处理这种常量时,通常把它放在了常量区中。而常量区则是始终存在的。

后一个例子中函数fun的返回值就是一个指向这种常量区的指针。

函数返回指针,要使主程序可以使用这个指针来访问有意义的数据,关键就是要保证在使用这个指针值的时候,该指针所指向的地方的数据仍然有意义。

还有,如果指针是指向函数的指针,那么这个指针就是指向程序代码区的。这也是一种应用的情况。
另外,如果明白了它的原理,程序员还可以发明出一些其他灵活的使用方法,当然,那都属于“怪”方法,一般不提倡的。

程序三:

int main()

{

  int a,b;

  int max;

  int fun (int a,int b);

  scanf("%d%d",&a,&b);

  max=fun (a,b);

  printf("\n%d\n",max);

  return 0;

};
//http://www.bianceng.cn
int fun(int a,int b)

{

  int max;

  if(a>b)

    max=a;

  else

    max=b;

  return max;

}

//可以正确返回

程序三:

这个例子中,返回的不是变量max的地址,返回的是它的值。

return后面的东西,看做一个表达式,返回的是这个表达式的值。

例如,入口如果a是3,b是5,则此时(执行return语句时)max里面存的是5。而return语句的功能就是把max里面的5取出来,放到“返回值寄存器”中。

主程序是从“返回值寄存器”得到这个5的(此时max变量已经不存在了)。

你前面的第二个例子中,同样,指针变量str在函数结束后已经不存在了。但是在return语句中,把指针变量str里面的值(等于字符串"hello"存放处的地址)送到“返回值寄存器”中了。

动态变量str不存在了,但常量区中的字符串"hello"还存在。主程序根据返回的地址就可以找到该字符串。

程序四:

int main()

{

  char *p;

  char *fun(void);

  p=fun();

  printf("%x\n",p);

  printf("%s\n",p);

  return 0;

}

char* fun(void)

{

//  char str[]={'a','b','c','d','e','f','\0'};

  char str[]="hello";

  printf("%x\n",str);

  return str;

}

//不能正确返回

char str[]="hello"; 是在动态变量区中开辟了可以容纳6个字符的数组,数组名叫str。同时将字符串"hello"(原存放于常数空间)拷贝到这个数组空间中去作为数组的初始化值。

此时若执行return str; 其中的str是数组名。C语言规定,表达式中如果是数组名,则该表达式的值就等于这个数组的地址。所以返回的是这个数组的地址,请注意:并不是字符串常量"hello"的地址!而函数结束时,虽然常数空间并不破坏,但这个数组空间是破坏了的,而你返回的却不是常数空间里的地址而正是已经破坏了的数组的地址。

而char *str="hello"; 是在动态变量区中开辟了一个可以存放一个指针值的变量,名叫str。同时将原存放于常数空间的字符串"hello"的地址赋给这个指针变量作为初始值。

此时若执行return str; 其中的str是指针变量名。C语言规定,表达式中如果是变量名,则该表达式的值就等于这个变量的值(指针变量的值就是地址)。所以返回的是变量str的值,而变量str的值就等于字符串常量"hello"的地址。而函数结束时,变量str破坏了的,但常数空间中的字符串并不破坏。主程序根据返回的地址就可以找到该字符串。

【总结】

常规程序中,函数返回的指针通常应该是:

(1)指向静态(static)变量;
(2)指向专门申请分配的(如用malloc)空间;
(3)指向常量区(如指向字符串"hello");
(4)指向全局变量;
(5)指向程序代码区(如指向函数的指针)。

除这5项以外,其它怪技巧不提倡。

函数内的变量,没有关键字static修饰的变量的生命周期只在本函数内,函数结束后变量自动销毁。当返回为指针的时候需要特别注意,因为函数结束后指针所指向的地址依然存在,但是该地址可以被其他程序修改,里面的内容就不确定了,有可能后面的操作会继续用到这块地址,有可能不会用到,所以会出现时对时错的情况,如果需要返回一个指针而又不出错的话只能调用内存申请函数

返回结构体:

#include <stdio.h>

typedef struct {

      int a;

      int b;

      int c;

    }str;

str change(str s)

{

  s.a += 1;

  s.b += 1;

  s.c += 1;

  return s;

}

int main(void)

{

  str s1, s2;

  s1.a = 1;

  s1.b = 1;

  s1.c = 1;

  s2 = change(s1);

  printf("s1.a = %d\ts1.b = %d\ts1.c = %d\n",s1.a, s1.b, s1.c);

  printf("s2.a = %d\ts2.b = %d\ts2.c = %d\n",s2.a, s2.b, s2.c);

  return 0;

}

//可以返回

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

时间: 2017-06-22

C语言数据结构之 折半查找实例详解

数据结构 折半查找 实例代码: /* 名称:折半查找 语言:数据结构C语言版 编译环境:VC++ 6.0 日期: 2014-3-26 */ #include <stdio.h> #include <malloc.h> #include <windows.h> #define N 11 // 数据元素个数 typedef int KeyType; // 设关键字域为整型 typedef struct // 数据元素类型 { KeyType key; // 关键字域 int

C语言中双向链表和双向循环链表详解

双向链表和双向循环链表 和单向链表相比,多了一个前驱结点.如果他为空,那么next和prior都指向自己.而对于双循环链表,只需要最后一个元素的next指向head->next,head->next的prior指向最后一个节点即可. 插入操作 新节点s插入链表,s->next给p结点,s->prior给p->prior,然后,p->prior->next指向s,p->prior再指向s.顺序需要注意 s->next = p; s->prior =

C语言数据结构树的双亲表示法实例详解

1.树的双亲表示法: 树的双亲表示法 2./* bo6-4.c 树的双亲表存储(存储结构由c6-4.h定义)的基本操作(14个) */ Status InitTree(PTree *T) { /* 操作结果: 构造空树T */ (*T).n=0; return OK; } void DestroyTree() { /* 由于PTree是定长类型,无法销毁 */ } typedef struct { int num; TElemType name; }QElemType; /* 定义队列元素类型

C语言用栈实现十进制转换为二进制的方法示例

本文实例讲述了C语言用栈实现十进制转换为二进制的方法.分享给大家供大家参考,具体如下: #include<stdio.h> #include<malloc.h> #include<math.h> #include<string.h> #include "process.h" #define SIZE 100 #define STACKINCREMENT 10 #define OK 1 #define ERROR 0 #define TRU

C语言实现图的搜索算法示例

本文实例讲述了C语言实现图的搜索算法.分享给大家供大家参考,具体如下: 在游戏中,常常遇到路径规划问题,用到图的相关算法,我们以简单图来学习. 图通常有两种表示方式,矩阵和邻接表.矩阵表示简单,运算快,但当矩阵是稀疏矩阵的时候就存在空间浪费的问题,并且效率也会下降,而邻接表节约空间,并且由于边是连续访问,时间效率也比较高.在本文中,我们将以邻接表来表示图. #include<queue> #include<stack> using namespace std; struct SE{

C语言数据结构算法之实现快速傅立叶变换

C语言数据结构算法之实现快速傅立叶变换 本实例将实现二维快速傅立叶变换,同时也将借此实例学习用c语言实现矩阵的基本操作.复数的基本掾作,复习所学过的动态内存分配.文件操作.结构指针的函数调用等内容. 很久以来,傅立叶变换一直是许多领域,如线性系统.光学.概率论.量子物理.天线.数字图像处理和信号分析等的一个基本分析工具,但是即便使用计算速度惊人的计算机计算离散傅立叶变换所花费的时间也常常是难以接受的,因此导致了快速傅立叶变换(FFT)的产生. 本实例将对一个二维数组进行正.反快速傅立叶变换.正傅

Apache Commons Math3探索之快速傅立叶变换代码示例

上一篇文章中我们了解了Apache Commons Math3探索之多项式曲线拟合实现代码,今天我们就来看看如何通过apache commons math3实现快速傅里叶变换,下面是具体内容. 傅立叶变换:org.apache.commons.math3.transform.FastFourierTransformer类. 用法示例代码: double inputData = new double[arrayLength]; // ... 给inputData赋值 FastFourierTran

深度学习开源框架基础算法之傅立叶变换的概要介绍

傅立叶变换时数字信号处理的重要方法之一,是法国数学家傅立叶在1807年在法国科学学会上发表的一篇文章中所提出的,在文章中使用了正弦函数描述温度分布,而且提出了一个著名的论断:任何连续性的周期信号都可以由一组适当的正弦曲线组合而成.而这个论断被当时审查论文的著名数学家拉格朗日所否定,拉格朗日认为正弦函数无法组合成一个个带有棱角的信号,但是从无限逼近的角度考虑,可以使用正弦函数来非常逼近期直到表示方法不存在明显差异,这篇论文最终在在拉格朗日死后15年之久才得以发表. 傅立叶变换的分类 根据信号是是周

python 图像的离散傅立叶变换实例

图像(MxN)的二维离散傅立叶变换可以将图像由空间域变换到频域中去,空间域中用x,y来表示空间坐标,频域由u,v来表示频率,二维离散傅立叶变换的公式如下: 在python中,numpy库的fft模块有实现好了的二维离散傅立叶变换函数,函数是fft2,输入一张灰度图,输出经过二维离散傅立叶变换后的结果,但是具体实现并不是直接用上述公式,而是用快速傅立叶变换.结果需要通过使用abs求绝对值才可以进行可视化,但是视觉效果并不理想,因为傅立叶频谱范围很大,所以要用log对数变换来改善视觉效果. 在使用l

C语言数据结构之二叉树的非递归后序遍历算法

C语言数据结构之二叉树的非递归后序遍历算法 前言: 前序.中序.后序的非递归遍历中,要数后序最为麻烦,如果只在栈中保留指向结点的指针,那是不够的,必须有一些额外的信息存放在栈中. 方法有很多,这里只举一种,先定义栈结点的数据结构 typedef struct{Node * p; int rvisited;}SNode //Node 是二叉树的结点结构,rvisited==1代表p所指向的结点的右结点已被访问过. lastOrderTraverse(BiTree bt){ //首先,从根节点开始,

C语言数据结构二叉树简单应用

 C语言数据结构二叉树简单应用 在计算机科学中,二叉树是每个节点最多有两个子树的树结构.通常子树被称作"左子树"(left subtree)和"右子树"(right subtree),接下来我就在这里给大家介绍一下二叉树在算法中的简单使用: 我们要完成总共有 (1)二叉树的创建 (2)二叉树的先中后序递归遍历 (3)统计叶子结点的总数 (4)求树的高度 (5)反转二叉树 (6)输出每个叶子结点到根节点的路径 (7)输出根结点到每个叶子结点的路径. 定义二叉树结点类型

C语言数据结构之模式匹配字符串定位问题

C语言数据结构之模式匹配字符串定位问题 主要实现了三种字符串的模式匹配,主要包括字符串子操作的集合,字符串指针回溯,和KMP算法 头文件  #ifndef INDEXHEAD_H_INCLUDED #define INDEXHEAD_H_INCLUDED #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXLEN 255 typedef char Sstring[MAXLEN + 1

C语言 数据结构之中序二叉树实例详解

C语言数据结构 中序二叉树 前言: 线索二叉树主要是为了解决查找结点的线性前驱与后继不方便的难题.它只增加了两个标志性域,就可以充分利用没有左或右孩子的结点的左右孩子的存储空间来存放该结点的线性前驱结点与线性后继结点.两个标志性域所占用的空间是极少的,所有充分利用了二叉链表中空闲存的储空间. 要实现线索二叉树,就必须定义二叉链表结点数据结构如下(定义请看代码): left leftTag data rightTag right 说明: 1.       leftTag=false时,表示left

c语言 数据结构实现之字符串

c语言 数据结构实现之字符串 串采用定长顺序存储结构(由c4-1.h定义)的基本操作(13个),包括算法4.2,4.3,4.5   实现效果图: #include <stdio.h> #include <string.h> #include <malloc.h> // SString是数组,故不需引用类型 #define OK 1 #define TRUE 1 #define FALSE 0 #define ERROR 0 #define INFEASIBLE -1 #

C语言数据结构之中缀树转后缀树的实例

C语言数据结构之中缀树转后缀树的实例 对于一个中缀表达式 a+b*c*(d-e/f) 转换成后缀是这样的形式 abc*def/-+ 后缀表达式是相当有用处的,转换成后缀表达式后求值会简单很多.那么该如何转换呢? 网上关于这方面的资料一搜一大把,每本数据结构的书中都会提及这个算法,在这个算法中,用到 栈 这个数据结构. 1,关键是比较运算符的优先级,谁的优先级高,谁就出现在前面上面的表达式中,有括号的时候括号优先级最高,*/次之,+-最后. 在上面的表达式中+的优先级不如*的高,因此,在后缀表达式