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

malloc分配的char*出现随机内容及栈溢出问题咨询

关于C语言print_file_results函数的内存异常与栈溢出问题

问题代码

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

int bytes_flag,lines_flag, words_flag;
int arg_in;
static struct option long_opts [] = {
    {"bytes", no_argument, 0, 'c'},
    {"lines", no_argument, 0, 'l'},
    {0,0,0,0}
};

int count_bytes(const char *filename){
    FILE * file_stream;
    int byte_count = 0;

    file_stream = fopen(filename, "r");
    
    if (file_stream == NULL){
        printf("File could not be opened.\n");
    }
    else{
        while (getc(file_stream) != EOF){
            byte_count ++;
        }
        fclose(file_stream);
    }
    return byte_count;
}

void print_file_results(const int bytes, const int lines, const int  words, const char *filename, const int size){
    char * results = malloc(size * 2 + 1);
    printf(results);
    printf("\n");
    char int_buffer[4];
    if (bytes != 0) {
        sprintf(int_buffer, "%d ", bytes);
        strcpy(results, int_buffer);
        printf(results);
        printf("\n");
    }
    if (lines != 0) { 
        //TODO
    }
    if (words != 0) {
        //TODO
    }
    printf("%s%s\n", results, filename);
    free(results);
    return;
}

int main (int argc, char * argv[]) {

    while(1){
        arg_in = getopt_long (argc, argv, "cl", long_opts, NULL);

        if (arg_in == -1){
            break;
        }
        switch(arg_in){
            case 'c':
                printf("Byte count\n");
                bytes_flag = 1;
                break;
            case 'l':
                printf("Line count\n");
                lines_flag = 1;
                break;
            default:
                abort();
        }
    }

    if (optind < argc){
        while (optind < argc){
            int bytes_total = 0;
            int lines_total = 0;
            int words_total = 0;

            printf("Current file %s\n", argv[optind]);

            if ( bytes_flag ){
                bytes_total = count_bytes(argv[optind]);
            }
            if (lines_flag){
                continue;
            }
            if (words_flag){
                continue;
            }

            print_file_results(bytes_total, lines_total, words_total, argv[optind] , bytes_flag+lines_flag+words_flag);
            optind++;
        }
    }
    else {
        printf("No files given\n");
        exit(1);
    }
    exit(0);
}

运行命令与异常输出

❯ ./ccwc.o -c test.txt
Byte count
Current file test.txt
ation is committed to coa
342190 
342190 test.txt
*** stack smashing detected ***: terminated
[1]    125314 IOT instruction (core dumped)  ./ccwc.o -c test.txt

问题原因分析

1. results出现随机文本的原因

  • malloc分配的内存块是未初始化的,保留着之前程序遗留的垃圾数据。你在strcpy初始化results之前就调用printf(results),直接输出了这块未初始化内存的随机内容,这就是看到的乱码。
  • 你用bytes_flag+lines_flag+words_flag作为内存计算的size参数,当仅启用-c时,size值为1,分配的内存只有3字节。但sprintf(int_buffer, "%d ", bytes)生成的字符串(比如示例中的"342190 ")长度远超3字节,strcpy(results, int_buffer)会直接超出results的内存范围,写入相邻内存区域,导致内存越界,产生不可预测的内容。

2. 栈溢出检测触发的原因

  • 你定义的int_buffer[4]仅4字节,但当bytes值为342190时,"%d "格式化后会生成7个字符(含空终止符),sprintf会把这些内容写入int_buffer,超出其容量,直接破坏栈上的其他数据(比如栈帧返回地址),触发栈溢出检测机制。

修复方案

  1. 初始化堆内存:用calloc代替malloc,或者分配后用memset(results, 0, required_size)初始化,避免输出未初始化的垃圾数据。
  2. 动态计算内存需求:不要用标志位数量计算内存,而是通过snprintf(NULL, 0, format_str)获取格式化后的字符串长度,再分配对应大小的内存。
  3. 避免栈缓冲区溢出:不要固定int_buffer的大小,要么动态分配,要么使用snprintf限制写入长度,防止越界。

修改后的print_file_results示例:

void print_file_results(const int bytes, const int lines, const int words, const char *filename){
    // 先计算所需总长度
    int total_len = 0;
    if (bytes != 0) {
        total_len += snprintf(NULL, 0, "%d ", bytes);
    }
    if (lines != 0) {
        total_len += snprintf(NULL, 0, "%d ", lines);
    }
    if (words != 0) {
        total_len += snprintf(NULL, 0, "%d ", words);
    }
    total_len += strlen(filename) + 1; // 文件名加终止符

    char *results = malloc(total_len);
    if (!results) { // 检查内存分配是否成功
        perror("malloc failed");
        return;
    }
    results[0] = '\0'; // 初始化空字符串

    if (bytes != 0) {
        snprintf(results + strlen(results), total_len - strlen(results), "%d ", bytes);
    }
    if (lines != 0) {
        snprintf(results + strlen(results), total_len - strlen(results), "%d ", lines);
    }
    if (words != 0) {
        snprintf(results + strlen(results), total_len - strlen(results), "%d ", words);
    }
    strcat(results, filename);
    printf("%s\n", results);

    free(results);
}

同时修改main中的调用,去掉最后一个size参数:

print_file_results(bytes_total, lines_total, words_total, argv[optind]);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 12:05:08