使用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,
崩溃原因分析
- 栈溢出:系统默认栈大小通常在8MB左右(Linux环境),当K=7时,
char s[(int)pow(10, K) + 2]会在栈上分配约10MB空间,直接超出栈的承载上限,导致栈帧错乱,触发段错误。调试器中出现的代码执行顺序混乱(比如先执行循环内的snprintf再定义数组)就是栈溢出破坏栈帧后的表现。 - 浮点数精度问题:
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
相关产品推荐
相关产品推荐

