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

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

[复制链接]
gaosmile 发布时间:2020-3-30 12:39
C语言函数为什么不能返回数组?, v/ l2 u# Z, |8 x, T
在C语言程序开发中,我们不可以编写下面这样的代码:
/ N. M$ i4 A5 T# `

  1. & l  v1 c; i& k" R% a
  2. char f(void)[8] {
      e* \9 w  Y7 V+ S" X" @
  3. char ret;
    . I# o7 u4 Z$ ?/ Z5 w# G7 X  I
  4. // ...fill...
    - |* U, i" O- h$ j$ `2 K; i# ~
  5. return ret;
    + G( X( a$ F* e& [7 d  q
  6. }
    ) E& D) b6 R: f4 H* X; y
  7. int main(int argc, char ** argv) {
    ' N& j9 I3 D$ g
  8. char obj_a[10];
    2 I4 F& K$ Z; q6 ^1 y! }
  9. obj_a = f();
    8 ^( N( d+ J8 i, k
  10. }
复制代码
0 ]2 E& m: h) _. t
微信图片_20200330123740.jpg
% j. y2 ^( M9 d0 S1 ~2 |" ^不可以编写这样的代码* }* N) k* j5 n6 X( y6 h' k

0 k1 r1 \) y* y- s5 W6 p
这其实就是不能在C语言函数中返回数组。但是如果将数组定义在结构体里面,就可以将其返回了,例如下面这段C语言代码,请看:
' e! v! a2 x5 z7 P/ {1 f* g/ a# _) f" N/ k+ F" l6 E- B1 I; }7 N6 {0 j
  1. ; [7 g6 }( M: B1 y
  2. struct s { char arr[10]; };
    - F$ w$ f9 B3 }+ z0 y
  3. struct s f(void) {
    0 ~( b( `) l3 A, }6 b
  4. struct s ret;+ i' D  U  `0 F5 ^1 w
  5. // ...fill.../ }- P" N# Q5 c# T
  6. return ret;) F2 |" l$ i9 r
  7. }
    % V4 F' k8 @$ Y0 y
  8. int main(int argc, char ** argv) {: F* M  s" t5 J
  9. struct s obj_a;) S7 h! q' ]! N/ ^
  10. obj_a = f();
    . m4 A9 {& A9 T
  11. }
复制代码

7 y% F) ?1 ?. ~( L 微信图片_20200330123743.jpg 0 Y" @1 I; |+ X( O% W: O% L3 C0 ^
函数可以返回结构体

  b. ^- [# f. n/ f! i' T) k结构体 s 只有一个数组成员 arr,显然,函数可以返回结构体,即使结构体只有一个数组成员,这是为什么呢?
C语言没有严格意义上的“数组类型”  J" `; P1 R/ r. z
基本上,C语言中的数据结构可以分为两类,第一类数据结构可以被赋值,而第二类数据结构不可以被赋值,数组属于第二类数据结构。

8 N( b& ]$ i" e0 a% h4 \7 }除了数组,还有其他第二类数据结构吗?
我想基本上没有了,除非把函数算上。
与函数不能返回数组密切相关的事实是,C语言没有严格意义上的“数组类型”。可能从C语言代码角度来看,似乎有数组类型的变量,但是如果尝试将该变量像其他变量一样使用,得到的实际上是指向数组第一个元素的指针。例如下面这段C语言代码:
* X# u+ c7 p1 K9 A! T; m$ W# U) m  G

  1. , W9 E9 S: w( x* i& W! i3 b1 e
  2. char a[10], b[10];6 m1 e: ]5 u8 |5 K4 y  _
  3. a = b;
复制代码
- I; Q/ _9 g7 C8 z6 z& r$ e) T
这并不能把数组 b 的内容拷贝给数组 a,实际上,上面两行C语言代码相当于下面这一行:7 O2 l5 w: f! h! [- {* [
  1. a = &b[0];
复制代码
- J. h4 P1 V8 P/ P2 }

& c% p6 i; |2 q( {5 t

: v- y( d2 C) z# H显然,左边是数组 a,而右边其实是一个指针。即使数组在某种程度上可以看作能够被赋值,但我们有很大几率得到类型不匹配,例如下面这段C语言代码:* j( A9 _+ u" z/ z
  1. + T( m% n% i0 L) U% K; R
  2. a = f();
复制代码

( Z  O) U% {7 _( h6 G

' t% B: H7 W8 }4 y  a" u8 M) _1 W- d: X- A
这里假设 f() 是一个返回数组的函数,它的核心C语言代码如下:
! z5 j. t" l8 Y

  1. * O6 ^" X( N) E; G0 z
  2. char ret[10];
    4 G3 `$ ~: U: z( A8 `
  3. /* ... fill ... */
    2 j! j% M/ m* C) U5 B
  4. return ret;
复制代码
& w6 M1 p: k2 S& E
0 i' T" I* i, P
5 q5 w4 H- K1 b8 {. F+ ^
不过按照前面所说的,其实上面的返回语句相当于下面这一句:/ V$ [/ e  u8 w5 n3 q
  1. return &ret[0];
    / H: X# K+ ~- a& r' G2 V+ L
复制代码
& v' r+ y: M& W0 X: C4 W6 Y  h% G

- f4 z8 w: A7 ^7 |" y同样的,我们若是尝试将数组赋值给 a,最终实际得到仍然是将指针赋值给 a,熟悉C语言语法的读者应该能够看出不妥之处。
6 w; ?% Y2 F) y0 L) o为什么把数组塞入结构体,情况就不同了呢?
; K% p3 Z: x& Q4 Y/ y: x- \
文章开头提到,虽然C语言的数组不可以被赋值,但是将其塞入结构体就可以赋值了。
这是什么原因呢?
$ P& I' C4 _8 |
其实这涉及到C语言的设计初衷,以及相关的一些发展历史了。
C语言在语法和语义上与机器硬件很接近,它的基本操作可以被编译为一个或者几个机器指令,占用若干个处理器周期。

3 W3 w9 J& h# O# r& J9 V( @; ^. W# DC语言中的数组是特殊的,它与指针一直都是非常暧昧的。
这种暧昧的关系从C语言的前身B语言就开始了,并一直延续至今,而今天的结构体语法最初并不是包含在C语言中的。

1 }6 s, C: `, K# q因为C语言数组与指针的暧昧关系,编译器也很难区分它们,所以我们不可能为C语言数组赋值。
而且由于“赋值”操作也属于C语言的基本操作,为了贴合硬件,要求其必须在几个处理器周期完成,所以单个的“赋值”运算符 = 基本上不可能扩展到需要几千乃至几万个机器周期,以对成千上万个数组元素赋值。
5 T3 j0 Y& o$ D% l: H
基于这样的原理,早期的C语言其实连结构体赋值都是不支持的。
. s6 p. J3 V  ~: f6 E! o
到这里,相信不少读者又有疑问了,既然C语言的基本操作需要控制在少量的机器周期内,那为什么结构体赋值却是支持的呢?
毕竟C语言中的结构体也是可以包含多个字节信息的。
/ ^5 {' {0 {* c. C( u7 D3 _2 ^. _
C语言中的结构体也是可以包含多个字节信息的

! e4 `' f1 G/ R1 B5 M( k正如前文所说,早期的C语言的确不支持结构体赋值,但是在后来的发展中却增加了结构体赋值能力。
对此只能说是结构体幸运,“将C语言基本操作控制在少量机器周期内”只是一个准则,而不是限制。

+ o/ b' j# X; [; u* P1 H' F要知道,C语言结构体通常很小,只有几十到几百字节,增加结构体赋值能力无疑能够大大方便程序员编写代码。
大多数情况下,结构体赋值操作并不会严重“超时”,这其实是一种平衡。
: K' i2 ]$ [1 u1 c/ J9 g2 g
我之前的文章曾经讨论过,程序设计语言一般都要处理一个天平,天平的两端分别是机器和程序员,如果追求极致的机器效率,将编程语言设计的十分精简,那么程序员就会非常痛苦。因此,即使是C语言,在追求高效率的同时,也要兼顾程序员的感受,所以稍稍违背一些设计准则,增加一些便利操作也是无可厚非的。
1 B% ^% Z8 w0 g4 c$ ?! U+ x小结
* e9 u+ Z1 b, f3 ]) [
4 w# R7 O. d6 P6 k* z# w5 k7 e+ x
C语言不支持数组赋值,更多的原因是C语言本身的特点(贴合硬件)以及一些历史原因。不过,如果真的希望对数组赋值,也是有一些技巧的,例如将数组塞入结构体。
收藏 评论0 发布时间:2020-3-30 12:39

举报

0个回答

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版