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

C语言使用%s读取连续字符串出现段错误,求非静态数组解决方案

字符串读取段错误问题解决(不使用静态字符数组)

问题描述

希望通过%s格式说明符从用户处获取字符串,并将其基地址存储在字符指针中。但连续读取两个或三个字符串时,第一个字符串能正常读取,从第二个开始出现段错误。测试代码如下:

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

int main() 
{
    char *s1, *s2, *s3;

    printf("Enter the first string: ");
    fflush(stdin);
    scanf("%s", s1);
    fflush(stdout);
    printf("%s\n", s1);

    printf("Enter the second string: ");
    fflush(stdin);
    scanf("%s", s2);
    fflush(stdout);
    printf("%s\n", s2);

    printf("Enter the third string: ");
    fflush(stdin);
    scanf("%s", s3);
    fflush(stdout);
    printf("%s\n", s3);
    return 0;
}

问题根源

代码里的char *s1, *s2, *s3是未初始化的野指针,指向的内存地址随机且未被程序授权使用。第一次scanf写入时碰巧没触发错误,但后续写入会覆盖非法内存区域,直接引发段错误。另外,fflush(stdin)属于未定义行为,标准C中fflush仅对输出流有效。

解决方案(不使用静态字符数组)

1. 手动用malloc分配内存

先预估输入字符串的最大长度,用malloc分配对应大小的内存,用完后必须用free释放,避免内存泄漏。

修正代码:

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

#define MAX_INPUT_LEN 100  // 根据实际需求调整最大长度

int main() 
{
    char *s1 = malloc(MAX_INPUT_LEN);
    char *s2 = malloc(MAX_INPUT_LEN);
    char *s3 = malloc(MAX_INPUT_LEN);

    // 检查内存分配是否成功
    if (!s1 || !s2 || !s3) {
        perror("malloc failed");
        return 1;
    }

    printf("Enter the first string: ");
    // 用%99s限制读取长度,防止缓冲区溢出
    scanf("%99s", s1);
    printf("%s\n", s1);

    printf("Enter the second string: ");
    scanf("%99s", s2);
    printf("%s\n", s2);

    printf("Enter the third string: ");
    scanf("%99s", s3);
    printf("%s\n", s3);

    // 释放分配的内存
    free(s1);
    free(s2);
    free(s3);
    return 0;
}

2. 使用scanf的m修饰符(C11及以上标准)

%ms格式会让scanf自动分配足够内存存储输入字符串,无需手动预估长度,但要注意:

  • 编译器需支持C11或更高版本
  • 必须用free释放scanf分配的内存

修正代码:

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

int main() 
{
    char *s1 = NULL, *s2 = NULL, *s3 = NULL;

    printf("Enter the first string: ");
    // %ms自动分配内存,需传递指针的地址
    if (scanf("%ms", &s1) != 1) {
        perror("scanf failed");
        return 1;
    }
    printf("%s\n", s1);

    printf("Enter the second string: ");
    if (scanf("%ms", &s2) != 1) {
        perror("scanf failed");
        free(s1);  // 已分配的内存要提前释放
        return 1;
    }
    printf("%s\n", s2);

    printf("Enter the third string: ");
    if (scanf("%ms", &s3) != 1) {
        perror("scanf failed");
        free(s1);
        free(s2);
        return 1;
    }
    printf("%s\n", s3);

    // 释放所有动态分配的内存
    free(s1);
    free(s2);
    free(s3);
    return 0;
}

额外注意事项

  • 禁止使用fflush(stdin),若要清理输入缓冲区残留字符,可用getchar()循环读取直到换行。
  • 使用scanf读取字符串时,必须限制读取长度(如%Ns,N为缓冲区大小减1),防止缓冲区溢出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 12:35:05