你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

C语言函数为什么不能返回数组?

[复制链接]
gaosmile 发布时间:2020-3-30 12:39
C语言函数为什么不能返回数组?! L& @* o2 {: L; m
在C语言程序开发中,我们不可以编写下面这样的代码:! \. B4 Y+ |) c5 d' ?3 z

  1. 7 C# \$ w/ y" M9 f5 F
  2. char f(void)[8] {
    % K8 W! @5 a' d1 s; d9 f6 Z. u0 w
  3. char ret;
    ; V% H! b! s; x  U: b, b- Q+ J
  4. // ...fill...
      Q; N7 g1 K+ S4 O
  5. return ret;( g5 G- Y1 j5 j
  6. }( Q* Y' |- l5 N2 B( F4 v3 l
  7. int main(int argc, char ** argv) {& E& O$ t  F7 r6 C( ?
  8. char obj_a[10];
    " M& C2 [" L1 A9 I0 o; K
  9. obj_a = f();. g9 I1 u+ S2 x) C1 W' ~
  10. }
复制代码

' `8 r0 K* t7 h: j8 [$ m- B 微信图片_20200330123740.jpg # L/ Y$ Q& Y# P0 @2 n3 H3 Z
不可以编写这样的代码8 H* S- W- X( m# n
% a# o, e% i( l; |
这其实就是不能在C语言函数中返回数组。但是如果将数组定义在结构体里面,就可以将其返回了,例如下面这段C语言代码,请看:) b! Z: m5 a" u0 p

2 `3 t' z. y- \

  1. & A9 _. c' @* Y+ V. W) E
  2. struct s { char arr[10]; };
    6 [# `+ T; F' A
  3. struct s f(void) {. E0 D% E1 E; v6 b
  4. struct s ret;
    6 L3 c6 [4 W6 K) D% L
  5. // ...fill...
    ! O/ M$ o9 M  z6 G( E
  6. return ret;
    5 L5 r% q9 a1 p/ K. l- u7 o' x+ s
  7. }
    1 H4 Q5 ^3 F: Z* v% W. |
  8. int main(int argc, char ** argv) {% ~0 c% O: `: s9 e, k" O; X
  9. struct s obj_a;4 E9 S( W+ ~# G" X0 q) [
  10. obj_a = f();" |9 r7 w. y3 v- z6 N; b. H
  11. }
复制代码

" B! ]" C  h) D 微信图片_20200330123743.jpg / J- T+ V* u9 R7 |
函数可以返回结构体

; Z' q4 T! W- x0 s结构体 s 只有一个数组成员 arr,显然,函数可以返回结构体,即使结构体只有一个数组成员,这是为什么呢?
C语言没有严格意义上的“数组类型”3 e# S4 |& x8 u0 j
基本上,C语言中的数据结构可以分为两类,第一类数据结构可以被赋值,而第二类数据结构不可以被赋值,数组属于第二类数据结构。
4 W& {% Q5 [$ b# b4 X$ P+ k9 X- V
除了数组,还有其他第二类数据结构吗?
我想基本上没有了,除非把函数算上。
与函数不能返回数组密切相关的事实是,C语言没有严格意义上的“数组类型”。可能从C语言代码角度来看,似乎有数组类型的变量,但是如果尝试将该变量像其他变量一样使用,得到的实际上是指向数组第一个元素的指针。例如下面这段C语言代码:
/ b7 U, V. |% N# w
  1. ' |7 c0 ?' i. g& V9 d4 c& G% T
  2. char a[10], b[10];: \5 _+ p: s% t2 B' C, t
  3. a = b;
复制代码
; A% p  B0 K9 ^
这并不能把数组 b 的内容拷贝给数组 a,实际上,上面两行C语言代码相当于下面这一行:
2 W, _) ]; Q" M. {6 `# |
  1. a = &b[0];
复制代码

& n  W) T. W; Q# i3 c
; d0 C, G3 L: f% w* a
2 F: q* t' ~8 W! v; O, n
显然,左边是数组 a,而右边其实是一个指针。即使数组在某种程度上可以看作能够被赋值,但我们有很大几率得到类型不匹配,例如下面这段C语言代码:
0 S3 J' ~9 v6 t

  1. ; |; ?' ^7 S! G& v
  2. a = f();
复制代码
7 y) g5 Q1 i) K

; ^) G7 _- {0 t# S2 r% F) M* ^0 Q4 |# y  T
这里假设 f() 是一个返回数组的函数,它的核心C语言代码如下:
2 m9 y' o4 y' F

  1. : ^% e1 J* z, h% [3 t  }, c
  2. char ret[10];/ P5 U! m9 Y  `, L8 G8 \- z
  3. /* ... fill ... */
    + \. a) a/ j# h: X3 D( X( B
  4. return ret;
复制代码

7 y& [/ V% n4 }; l% \( E. I

/ O4 s( Z8 e6 G. @$ t" V3 W& H; `$ i2 T, J
不过按照前面所说的,其实上面的返回语句相当于下面这一句:
& h# h2 x( J- i7 T/ `
  1. return &ret[0];
    - `* `5 m0 }( V
复制代码

9 y, V1 R# I. g  L; s! X, \4 E
4 N, |/ c  S) H% @! e# v同样的,我们若是尝试将数组赋值给 a,最终实际得到仍然是将指针赋值给 a,熟悉C语言语法的读者应该能够看出不妥之处。3 ^% A: n' `: H
为什么把数组塞入结构体,情况就不同了呢?

+ ~( ]4 K* g9 u0 T: [9 G文章开头提到,虽然C语言的数组不可以被赋值,但是将其塞入结构体就可以赋值了。
这是什么原因呢?
, @3 k" \& m" I8 z9 \
其实这涉及到C语言的设计初衷,以及相关的一些发展历史了。
C语言在语法和语义上与机器硬件很接近,它的基本操作可以被编译为一个或者几个机器指令,占用若干个处理器周期。

( x+ {/ T6 ~* I# E+ V3 t  |C语言中的数组是特殊的,它与指针一直都是非常暧昧的。
这种暧昧的关系从C语言的前身B语言就开始了,并一直延续至今,而今天的结构体语法最初并不是包含在C语言中的。

# {3 D2 U+ w6 u! p因为C语言数组与指针的暧昧关系,编译器也很难区分它们,所以我们不可能为C语言数组赋值。
而且由于“赋值”操作也属于C语言的基本操作,为了贴合硬件,要求其必须在几个处理器周期完成,所以单个的“赋值”运算符 = 基本上不可能扩展到需要几千乃至几万个机器周期,以对成千上万个数组元素赋值。
5 n* o7 M" E# t: _4 j9 P9 [$ a' o
基于这样的原理,早期的C语言其实连结构体赋值都是不支持的。

% y0 D; Z0 E" M2 y( k& h+ B0 T/ o# S到这里,相信不少读者又有疑问了,既然C语言的基本操作需要控制在少量的机器周期内,那为什么结构体赋值却是支持的呢?
毕竟C语言中的结构体也是可以包含多个字节信息的。
! g8 E" @8 |/ Z) y
C语言中的结构体也是可以包含多个字节信息的

+ I+ P+ x6 }1 j3 j正如前文所说,早期的C语言的确不支持结构体赋值,但是在后来的发展中却增加了结构体赋值能力。
对此只能说是结构体幸运,“将C语言基本操作控制在少量机器周期内”只是一个准则,而不是限制。
. A2 B6 h/ @/ |+ X$ Q1 ~
要知道,C语言结构体通常很小,只有几十到几百字节,增加结构体赋值能力无疑能够大大方便程序员编写代码。
大多数情况下,结构体赋值操作并不会严重“超时”,这其实是一种平衡。
* [' ]4 q, R3 Y+ f# r
我之前的文章曾经讨论过,程序设计语言一般都要处理一个天平,天平的两端分别是机器和程序员,如果追求极致的机器效率,将编程语言设计的十分精简,那么程序员就会非常痛苦。因此,即使是C语言,在追求高效率的同时,也要兼顾程序员的感受,所以稍稍违背一些设计准则,增加一些便利操作也是无可厚非的。/ V, B) a7 h+ T2 b% z. s
小结2 S% J" o6 N2 s9 J1 v% r: Q
- D7 H1 l0 u4 W7 q! G. U* V  @2 J
C语言不支持数组赋值,更多的原因是C语言本身的特点(贴合硬件)以及一些历史原因。不过,如果真的希望对数组赋值,也是有一些技巧的,例如将数组塞入结构体。
赞 收藏 评论0 发布时间:2020-3-30 12:39

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版