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

时间:2021-10-21 04:51:45

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

程序一:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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是在动态变量区,而该动态变量是局部的,函数结束时不保留的。

程序二:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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的返回值就是一个指向这种常量区的指针。

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

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

程序三:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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"还存在。主程序根据返回的地址就可以找到该字符串。

程序四:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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修饰的变量的生命周期只在本函数内,函数结束后变量自动销毁。当返回为指针的时候需要特别注意,因为函数结束后指针所指向的地址依然存在,但是该地址可以被其他程序修改,里面的内容就不确定了,有可能后面的操作会继续用到这块地址,有可能不会用到,所以会出现时对时错的情况,如果需要返回一个指针而又不出错的话只能调用内存申请函数

返回结构体:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#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;
 
}
 
 
//可以返回

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

原文链接:http://www.bianceng.cn/Programming/C/201702/50548.htm