问题引入
在C语言中,获取用户键盘录入的数据时,由于我们不知道用户到底要输入多少数据,即数据的大小是未知的,此时使用静态存储就比较困扰:输入数据小,静态空间浪费;输入数据大,静态空间不够
char s[100]; /* 静态空间 */
我们不妨试着编写一个可以动态分配内存空间的函数get_string();
代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* get_string(char*); /* 获取键盘录入的字符 */
int judge(void* name); /* 检查任意的指针是否为NULL */
int main(void)
{
char* s = get_string("请输入: ");
for(int i = 0, n = strlen(s); i <= n; i++)
printf("字符%c所对的ascll码值:%i\n", *(s + i), *(s + i));
free(s); /* 释放内存 */
return 0;
}
char* get_string(char* input)
{
printf("%s", input);
int size = 2;
char* s = malloc(sizeof(char) * size);
// 检查malloc分配内存情况
judge(s);
char c;
int count = 0; // 计数存了多少个字符在char* s中
while((c = getchar()) != EOF)
{
// 若空间不足
if(count + 1 >= size) /* 为什么要+1,因为字符串以'\0'结尾,多占一个字符空间,+1是为'\0'留的 */
{
size *= 2; /* 空间扩大两倍 */
char* t = malloc(sizeof(char) * size); /* t即临时变量,类似于值两两互换时的temp */
// 检查malloc分配内存情况
judge(t);
// 先copy旧的
for(int i = 0; i < size; i++)
t[i] = s[i];
free(s); /* 以前的没用了 */
t[size / 2] = '\0'; /* 字符串以NULL结尾,且strcpy也以这个为结束copy的标志 */
// strcpy
s = malloc(sizeof(char) * size);
// 检查malloc分配内存情况
judge(s);
strcpy(s, t);
free(t); /* 释放中间变量 */
}
if(c == '\n')
{
s[count] = '\0'; /* '\n' 即键盘录入的最后一个字符 */
break;
}
else
{
s[count] = c;
++count;
}
}
return s;
}
int judge(void* name) /* 判断任意类型的指针是否为NULL */
{
if(name == NULL)
{
printf("内存分配错误\n");
exit(EXIT_FAILURE); /* 如果是NULL的话,直接退出整个程序 */
}
return 0; /* 0即false,不是NULL */
}
效果展示
直接将键盘录入的字符输出:
分析
在编写get_string()函数时,其分配的内存大小是2n(size *= 2),也会导致空间的浪费,但是如果size += 1,则会导致时间复杂度增加——每增加一个元素,就要进行重新分配更大的空间,介入临时变量t,free等操作
且,以2n增长,所需空间会爆炸性增加,因此,我们不妨检测一下实际消耗的空间大小,如果实际使用的空间只占了size的1/4,不妨将size缩小一半
总之,进行动态分配时需要权衡,考虑时间复杂度和空间复杂度
Trade off!