You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言使用scanf()读取未知长度字符串的初始化方法

问题根因

你写的代码触发段错误的核心逻辑很简单:char *str = NULL 只是声明了一个字符指针,根本没有分配可写入的合法内存,scanf 拿到这个NULL指针会直接往非法地址写数据,必然触发内存访问错误。
另外要明确:C标准里的%s格式符不会自动帮你分配内存,你必须传入一块提前准备好的、足够容纳输入内容的可写内存,它才会正常工作。

可行方案

以下两种方案都满足「不需要预先知道输入字符串长度、不需要硬编码超大定长数组」的要求:

方案1:POSIX系统下用%ms修饰符(代码最简洁)

Linux、macOS等遵循POSIX标准的系统中,scanf的%s支持m修饰符,会自动根据实际输入的字符串长度申请对应大小的内存,完全不需要你提前预估长度:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char *str = NULL;
    int num;
    // 注意这里是%ms,传入str的地址,scanf会自己修改str指向新分配的内存
    int read_res = scanf("%ms %d", &str, &num);
    if (read_res != 2) {
        printf("输入格式不符合要求\n");
        return 1;
    }
    printf("str: %s\nnum: %d\n", str, num);
    free(str); // 必须手动释放scanf申请的内存,避免泄漏
    return 0;
}

这个方案代码量最小,但注意它不属于C语言标准特性,Windows下的MSVC编译器默认不支持,需要跨全平台兼容就用下面的方案。

方案2:逐字符读取+动态扩容(全编译器通用)

如果需要兼容不支持%ms的环境,可以自己实现动态扩容逻辑:逐字符读取输入,当前申请的内存装不下了就扩容一块,直到读到字符串和数字的分隔符为止,不需要提前知道输入长度:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char *str = NULL;
    int num;
    int cap = 0; // 已申请的内存总大小
    int str_len = 0; // 已读取的字符串长度
    char cur;

    // 先跳过字符串前的空白符(空格、换行、制表符)
    while ((cur = getchar()) != EOF && (cur == ' ' || cur == '\n' || cur == '\t'));
    if (cur == EOF) {
        printf("输入异常\n");
        return 1;
    }

    // 逐字符读字符串,碰到空白分隔符就停
    do {
        // 剩余空间不够存新字符+末尾的'\0'时就扩容,每次扩16字节即可,可按需调整步长
        if (str_len + 1 >= cap) {
            cap += 16;
            char *tmp = realloc(str, cap);
            if (!tmp) {
                free(str);
                printf("内存分配失败\n");
                return 1;
            }
            str = tmp;
        }
        str[str_len++] = cur;
        cur = getchar();
    } while (cur != EOF && cur != ' ' && cur != '\n' && cur != '\t');
    str[str_len] = '\0'; // C字符串必须补结束符,不然printf会读越界

    // 读完字符串剩下的部分直接读整数即可
    if (scanf("%d", &num) != 1) {
        free(str);
        printf("数字格式错误\n");
        return 1;
    }

    printf("str: %s\nnum: %d\n", str, num);
    free(str);
    return 0;
}

注意:所有通过malloc/realloc/%ms申请的堆内存,用完都必须手动调用free()释放,否则会出现内存泄漏。

内容的提问来源于stack exchange,提问作者mariekart42

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 02:27:20