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

使用strncpy时异常:构建千万位数字序列程序崩溃

拼接整数生成长序列程序崩溃排查与解决

问题描述

开发了一个通过拼接连续整数生成长数字序列的程序,当K=6(生成1百万位序列)时运行正常,但设置K=7(生成10百万位序列)时程序崩溃,调试器输出未提供明确线索。

原代码

#include <stdio.h>
#include <string.h>
#include <math.h>
// no segfault occurs for K<=6
#define K 7

int main() {
    char s[(int)pow(10, K) + 2];
    char *ptr_s = s;
    char *end = &s[(int)pow(10, K)];

    for (int i = 1;; i++) {
        char buf[K+2];
        snprintf(buf, K+1, "%d", i); // problemetic line
        if (ptr_s >= end) {
            break;
        }
        int len = strlen(buf);
        if (ptr_s + len > end) {
            len = end - ptr_s;
        }
        strncpy(ptr_s, buf, len);
        ptr_s += len;
    }

    int answer = 1;
    for (int i = 0; i <= K; i++) {
        answer *= s[(int)pow(10, i)-1] - '0';
    }
    printf("%d\n", answer);

    return 0;
}

调试器输出

(gdb) break 1
Breakpoint 1 at 0x401090: file euler.c, line 7.
(gdb) run
Starting program: /home/runner/CCC/euler 
warning: Error disabling address space randomization: Operation not permitted
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/nix/store/4nlgxhb09sdr51nc9hdm8az5b08vzkgx-glibc-2.35-163/lib/libthread_db.so.1".

Breakpoint 1, main () at euler.c:7
7   int main() {
(gdb) next
14          snprintf(buf, K+1, "%d", i);
(gdb) next
8       char s[(int)pow(10, K) + 2];
(gdb) next
12      for (int i = 1;; i++) {
(gdb) next
14          snprintf(buf, K+1, "%d", i);
(gdb) next

Program received signal SIGSEGV, Segmentation fault.
0x0000000000401127 in snprintf (__fmt=0x402004 "%d", __n=8, __s=0x7ffc0a7a431f "") at /nix/store/4pqv2mwdn88h7xvsm7a5zplrd8sxzvw0-glibc-2.35-163-dev/include/bits/stdio2.h:54
54    return __builtin___snprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,

崩溃原因分析

  1. 栈溢出:系统默认栈大小通常在8MB左右(Linux环境),当K=7时,char s[(int)pow(10, K) + 2]会在栈上分配约10MB空间,直接超出栈的承载上限,导致栈帧错乱,触发段错误。调试器中出现的代码执行顺序混乱(比如先执行循环内的snprintf再定义数组)就是栈溢出破坏栈帧后的表现。
  2. 浮点数精度问题:pow函数返回浮点数,强制转换为int时可能存在精度丢失。比如pow(10,7)理论值是10000000,但浮点数可能存储为9999999.999999998,转int后变成9999999,导致数组大小不足,后续操作越界。

解决方法

1. 改用堆内存分配大数组

栈空间有限,大数组必须用malloc在堆上分配,用完记得用free释放。

2. 替换pow函数,避免浮点数精度问题

用整数运算计算10的幂,或者直接预定义常量,确保数值准确。

3. 优化循环逻辑(可选)

提前计算需要拼接的整数范围,避免无意义的循环迭代。

修改后的代码示例

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

#define K 7

// 计算10的整数次幂,避免浮点数精度问题
long long power_of_10(int exponent) {
    long long result = 1;
    for (int i = 0; i < exponent; i++) {
        result *= 10;
    }
    return result;
}

int main() {
    long long seq_len = power_of_10(K);
    // 在堆上分配内存,检查分配是否成功
    char *s = malloc(seq_len + 2);
    if (!s) {
        fprintf(stderr, "内存分配失败\n");
        return 1;
    }

    char *ptr_s = s;
    char *end = s + seq_len;

    for (int i = 1;; i++) {
        char buf[K+2];
        snprintf(buf, sizeof(buf), "%d", i);
        if (ptr_s >= end) {
            break;
        }
        int len = strlen(buf);
        if (ptr_s + len > end) {
            len = end - ptr_s;
        }
        strncpy(ptr_s, buf, len);
        ptr_s += len;
    }

    int answer = 1;
    for (int i = 0; i <= K; i++) {
        long long index = power_of_10(i) - 1;
        answer *= s[index] - '0';
    }
    printf("%d\n", answer);

    // 释放堆内存
    free(s);
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 09:05:37