get_string——C语言实现

本文介绍了如何在C语言中通过get_string函数动态分配内存处理用户未知大小的键盘输入,讨论了不同内存分配策略对空间和时间复杂度的影响,强调了在动态内存管理中的时间和空间权衡问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题引入

​   在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()函数时,其分配的内存大小是2nsize *= 2),也会导致空间的浪费,但是如果size += 1,则会导致时间复杂度增加——每增加一个元素,就要进行重新分配更大的空间,介入临时变量t,free等操作
​   且,以2n增长,所需空间会爆炸性增加,因此,我们不妨检测一下实际消耗的空间大小,如果实际使用的空间只占了size的1/4,不妨将size缩小一半
​   总之,进行动态分配时需要权衡,考虑时间复杂度和空间复杂度
​   Trade off!

编译原理是计算机科学中的一个重要分支,主要研究如何将高级语言转换为机器语言的过程。其中,词法分析器是编译器中的一个重要组成部分,它负责将源代码中的字符序列转换为有意义的单词序列,也就是词法单元。 下面是一个简单的词法分析器的C语言代码示例: ```c #include <stdio.h> #include <ctype.h> #include <string.h> #define MAX_TOKEN_LEN 100 typedef enum { INT, FLOAT, IDENTIFIER, KEYWORD } TokenType; typedef struct { TokenType type; char value[MAX_TOKEN_LEN]; } Token; char *keywords[] = {"if", "else", "while", "for", "int", "float"}; int is_keyword(char *word) { int i; for (i = 0; i < 6; i++) { if (strcmp(word, keywords[i]) == 0) { return 1; } } return 0; } Token get_token() { Token token; char c = getchar(); while (isspace(c)) { c = getchar(); } if (isdigit(c)) { token.type = INT; int i = 0; while (isdigit(c)) { token.value[i++] = c; c = getchar(); } if (c == '.') { token.type = FLOAT; token.value[i++] = c; c = getchar(); while (isdigit(c)) { token.value[i++] = c; c = getchar(); } } token.value[i] = '\0'; ungetc(c, stdin); } else if (isalpha(c) || c == '_') { token.type = IDENTIFIER; int i = 0; while (isalnum(c) || c == '_') { token.value[i++] = c; c = getchar(); } token.value[i] = '\0'; ungetc(c, stdin); if (is_keyword(token.value)) { token.type = KEYWORD; } } else { token.type = c; } return token; } int main() { Token token; do { token = get_token(); switch (token.type) { case INT: printf("INT: %s\n", token.value); break; case FLOAT: printf("FLOAT: %s\n", token.value); break; case IDENTIFIER: printf("IDENTIFIER: %s\n", token.value); break; case KEYWORD: printf("KEYWORD: %s\n", token.value); break; default: printf("%c\n", token.type); break; } } while (token.type != EOF); return 0; } ``` 这个词法分析器可以识别整数、浮点数、标识符和关键字。它通过一个`get_token()`函数来获取下一个词法单元,并根据单元的类型进行相应的处理。在`get_token()`函数中,它会读取输入流中的字符,根据字符的类型来判断当前单元的类型,并将单元的值存储在一个`Token`结构体中返回。在`main()`函数中,它会不断调用`get_token()`函数来获取下一个单元,并根据单元的类型进行相应的输出,直到读取到输入流的结尾。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值