经常有同学会问:C语言怎样根据实际的输入,来决定一个数组究竟要多大?也就是实现一个能自动适应我需求的“智能”数组,答案是:很遗憾!C语言没有这么高级的玩意儿。但这个需求又是如此的平常,怎么破?
现在,假设你要将你输入的数据放置到一个数组之中,你的代码可能如下:
char s[20]; fgets(s, 20, stdin);
以上代码的弊端在于:如果我的输入超过20个字符,数组 s 放不下。 如果我的输入不足20个字符,显然是一种浪费。
当然,你可能会说,可以用变长数组呀,look:
int n; scanf("%d", &n); // 先说好你要输入的字符长度 char s[n]; // 根据说好的 n 来定义数组 s fgets(s, n, stdin);
但是这样的代码几乎没有解决任何问题,首先我们无法将输入的长度丢给用户先行决定,而是应该让程序自动判断。更何况,用户输入了n之后未必就会严格按照n个字符的长度输入后续的字符。
而且本来输入一遍的事情,现在变成要输入两遍,群众情绪可能会暴走。
来想象一个真实场景,A和B两个人通过网络对话。
网络中传输的数据包一般会包含两类信息,一类是固定的信息,比如双方的IP、端口、本包协议头等,另一类是可变信息,比如某一次聊天的具体内容。
这两类信息一般被封装在一个结构体里面,比如:
struct msg { // 一些固定长度的信息 unsigned long local_address; unsigned long peer_address; unsigned short port; .... .... // 一些长度不确定的信息 char message[0]; };
注意到,以上代码出现一个长度为 0 的数组,这个数组在GNU的新语法中被支持,它仅仅是一个占位符,也就是其本身并不占用内存,那有什么用呢?
假设结构体 struct msg 中固定长度的信息为100个字节,那么在给对方发送
一段诸如 “ 你好!” 这样的字符串的时候,可以这么分配内存:
char *package = malloc(sizeof(struct msg) + sizeof(" 你好! "));
之后,就可以将数据 " 你好!" 放入该结构体的末尾部分,然后使用数组名 message 来索引。
当然,这么做只是一个小小伎俩而已,因为你首先还是要将 “ 你好!” 这个数据存储到一个指定的固定的、并且足够大的内存空间才能。这样做只是避免了每次都需要分配一个“足够大”的数组,而变成只指定一个就可以了。
说到这里你应该是失望的,的确,C语言没有像c++那样的string类型数据,实现智能的自身可变长度的变量,毕竟,C语言不是现代自动机枪,它只是一把专注效率的尖刀。很多事情都需要开发人员参与管理和优化,系统本身没有提供更多的智能。