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

使用栈上字符串作为strtol的endptr参数触发栈溢出的原因及相关疑问

使用栈上字符串作为strtol的endptr参数触发栈溢出的原因及相关疑问

看起来你对strtol的endptr参数的用法有个关键误解,这才导致了栈溢出的问题。咱们一步步拆解清楚:

先搞懂strtol的endptr到底是干嘛的

你可能误以为strtol会把转换后剩下的字符串复制到endptr指向的容器里,但完全不是这样!strtol的endptr参数本质是用来记录位置的:它要求传入一个char**类型的指针,strtol会把原字符串中第一个无法被转换的字符的地址,直接存在*endptr里。也就是说,它不需要你预先分配内存存剩余字符串,只是让这个指针指向原字符串里的某个位置而已。

你第一个能跑的代码其实也绕了弯路——根本不需要malloc内存给ptr,直接用一个栈上的char*变量就行,比如:

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

int main() {
    const char str[] = "12aaa";
    char *endptr; // 普通的char*指针变量
    long val = strtol(str, &endptr, 10);
    
    printf("str: %s\n", str);
    printf("strtol结果: %ld\n", val);
    printf("剩余部分: %s\n", endptr); // 直接输出endptr指向的内容,就是"aaa"
    
    return EXIT_SUCCESS;
}

这个代码和你第一个malloc版本的效果完全一样,但更简洁安全,也没有内存泄漏风险。

你的错误代码出问题的核心原因

咱们看你修改后的代码:

char container[] = "aaaaa"; // 栈上的char数组,长度5
printf("strtol: %ld\n", strtol(str, &container, 10));

这里有两个致命问题:

1. 类型完全不匹配

container是一个长度为5的char数组,&container的类型是char (*)[5]——也就是“指向长度为5的char数组的指针”,而strtol需要的参数类型是char**(指向char指针的指针)。

虽然编译器可能会给你一个警告(如果你没开警告的话一定要开!),但强行传参后,strtol会把&container当成char**来用:它会把原字符串中第一个无效字符的地址(比如str+2,也就是指向"12aaa"中第一个'a'的地址),写入到*endptr指向的位置——也就是container数组的起始地址。

2. 栈内存溢出

在64位系统中,一个指针的大小是8字节,而你的container数组只有5字节的空间。当strtol试图把8字节的指针值写入到只有5字节的栈数组里时,就会覆盖栈帧中数组后面的其他数据(比如main函数的返回地址、栈保护的cookie值)。这直接触发了GCC的栈溢出检测机制(*** stack smashing detected ***),程序被终止。

哪怕是32位系统(指针4字节),虽然不会立刻溢出,但你写入的是一个内存地址,而不是你以为的剩余字符串,container数组里会被填成乱码,后续访问也会出问题。

再解答你的几个小疑问

  • 为什么用char而不是const char?:其实你不需要把container改成非const——因为strtol根本不会修改原字符串,也不会修改你传入的container数组(它只是错误地往里面写了个指针值)。正确用法里的char* endptr是用来存地址的,和原字符串的const属性无关。
  • 栈变量的生命周期:你说的没错,container作为main函数里的栈变量,生命周期确实是到main执行完为止,但问题根本不是生命周期,而是你错误地用了数组的地址,导致类型不匹配和内存溢出。

最后给你几个建议

  1. 永远不要忽略编译器警告:比如类型不匹配的警告,这几乎都是bug的前兆。编译时加上-Wall -Wextra,能帮你提前发现很多问题。
  2. 仔细啃man手册:strtol的man页里明确写了endptr的作用:If endptr is not NULL, strtol() stores the address of the first invalid character in *endptr.——重点是“stores the address”,不是“copies the remaining string”。
  3. 区分数组和指针:C里的数组和指针是完全不同的东西,char arr[]是栈上的连续内存,&arr是指向整个数组的指针;而char* ptr是一个存储地址的变量,&ptr才是strtol需要的char**类型。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 11:43:00