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

调用load_dict后打印触发Segmentation Fault的问题排查求助

问题:调用load_dict函数后触发Segmentation Fault

我正在实现一个将字符串解析为英文数字书写形式的解析器,目前能正常获取数字并按指定格式存储解析结果。但在调用check_stored_numbers打印存储结果后,再调用load_dict函数,程序会触发段错误。


正常运行的代码及输出

代码

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

    read_input(&digits, &dictionary, argc, argv);
    check_stored_numbers();
}

输出

c2r6p4% ./a.out 24234

exp 0  units 234
exp 1  units 24% 

添加load_dict后的代码及错误输出

代码

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

    read_input(&digits, &dictionary, argc, argv);
    check_stored_numbers();
    load_dict(dictionary);
}

输出

c2r6p4% ./a.out 24234 
exp 0  units 234 
zsh: segmentation fault (core dumped)  ./a.out 24234

问题细节

解析后的数字存储在全局指针指向的全局数组中,已尝试简化代码,问题仍聚焦在上述调用顺序上。运行环境为Ubuntu,编译命令:cc * -Wall -Werror -Wextra。


完整代码

#include "functions.h"

int char_to_digit(char c)
{
    return (c - '0');
}

#include "functions.h"

void check_only_digits(char *digits)
{
    while (*digits != '\0')
    {
        if ((*digits >= '0') && (*digits <= '9'))
        {
            digits++;
        }
        else
        {
            ft_putstr("error");
            exit (1) ;
        }
    }
    return ;
}

#include "functions.h"

void free_mem(void *pointer)
{
    if (pointer != NULL)
        {
            free(pointer);
        }
}

#include "functions.h"

void    ft_openfile()
{
    char *conteudo = NULL;
    int arquivo;
    ssize_t tamanho;
    
    arquivo = open ("numbers.dict", O_RDONLY);
    if (arquivo == -1)
    {
        perror("Erro ao abrir arquivo");
        exit (1) ;
    }
    tamanho = lseek(arquivo, 0 , SEEK_END);
    conteudo = (char *)malloc(tamanho + 1);
    if (conteudo == NULL)
    {
        perror("Erro ao alocar memoria");
        close(arquivo);
        exit(1);
    }
    lseek(arquivo, 0, SEEK_SET);
    ssize_t bytes = read(arquivo, conteudo, tamanho);
    if (bytes == -1)
    {
        perror("Erro ao alocar memoria");
        free(conteudo);
        close(arquivo);
        exit (1) ;
    }
    conteudo[tamanho] = '\0';
    printf("arquivo:\n%s", conteudo);
    free(conteudo);
    close(arquivo);
}

#include "functions.h"

void    ft_putchar(char c)
{
    write(1, &c, 1);
}

void ft_putnbr(int nb)
{
    long    number;
    
    number = (long)nb;
    if (number < 0)
    {   ft_putchar('-');
        number = number * -1;
    }

    if (number < 10)
    {
        ft_putchar(number + '0');
    }

    if (number >= 10)
    {
        ft_putnbr(number / 10);
        ft_putnbr(number % 10);
    }
}

#include "functions.h"

void    ft_putstr(char (*str))
{
    int i;

    i = 0;
    while (str[i] != 0)
    {
        write(1, &str[i], 1);
        i++;
    }
}

#include "functions.h"

char    *ft_strcpy(char *dest, char *src)
{   
    int count;

    count = 0;
    while (src[count] != '\0')
    {       
        dest[count] = src[count];
        count++;
    }
    dest[count] = '\0';
    return (dest);
}

#include "functions.h"

int ft_strlen(char (*str))
{
    int i;

    i = 0;
    while (str[i] != '\0')
    {
        i++;
    }
    return (i);
}

#ifndef FUNCTIONS_H
#define FUNCTIONS_H

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include "types.h"

void    ft_putstr(char (*str));
void    ft_putchar(char c);
int     ft_strlen(char (*str));
void    ft_putnbr(int nb);
char    *ft_strcpy(char *dest, char *src);
void    check_only_digits(char *digits);
void    read_input_dict(char **dictionary, char *argv);
void    read_input_digits(char **digits, char *argv);
void    read_input(char **digits, char **dictionary, int argc, char **argv);
void    free_mem(void *pointer);
int     parse_blocks(char *digits);
void    str_end(char **str);
int     char_to_digit(char c);
void    store_user_numbers(char *digits);
int     parse_number(char **read_digits, char *digits);
void    load_dict(char *dict);

#endif

#include "types.h"

dict_num    *g_dict;
parsed_num *g_user_numbers;
int g_blocks = 1;

#include "types.h"

#ifndef GLOBALS_H
#define GLOBALS_H

extern dict_num    *g_dict;
extern parsed_num *g_user_numbers;
extern int g_blocks;

#endif

#include "functions.h"
#include "globals.h"

void    load_dict(char *dict)
{
    ft_strlen(dict);
    g_dict = malloc(sizeof(dict_num) * 41);

    g_dict[0].number.exponent = 0;
    g_dict[0].number.units = 0;
    g_dict[0].name = "zero";

    // a large number of lines

    g_dict[40].number.exponent = 36;
    g_dict[40].number.units = 1;
    g_dict[40].name = "undecillion";
}

#include "functions.h"
#include "globals.h"

void    check_stored_numbers()
{
    for(int i = 0; i < g_blocks; i++)
    {
        printf("\nexp %i  units %i", g_user_numbers[i].exponent, g_user_numbers[i].units);
    }
}

void    check_stored_dict()
{
    for(int i = 0; i < 41; i++)
    {
        printf("exp %i  units %i  name %s\n", g_dict[i].number.exponent, g_dict[i].number.units, g_dict[i].name );
    }
}

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

    read_input(&digits, &dictionary, argc, argv);
    check_stored_numbers();
    //load_dict(dictionary);
    
    //check_stored_dict();
    //free(dictionary);
    //free(digits);
    //free(g_user_numbers);
}

#include "functions.h"

int parse_blocks(char *digits)
{
    int number_of_digits;
    int number_of_blocks;

    number_of_digits = ft_strlen(digits);
    number_of_blocks = number_of_digits / 3;
    if ((number_of_digits % 3) != 0)
        number_of_blocks++;
    return (number_of_blocks);
}

#include "functions.h"

int power(int base, int exp)
{
    if (exp == 0)
        return (1);
    if (exp == 1)
        return (base);
    return (base * power(base, exp - 1));
}

int parse_number(char **read_digits, char *digits)
{
    int return_value;
    int count;

    count = 3;
    return_value = 0;
    while ((*read_digits != digits - 1) && (count >= 1))
    {
        return_value = return_value +(power(10, 3 - count) * (char_to_digit(**read_digits)));
        (*read_digits)--;
        count--;
    }
    return (return_value);
}

#include "functions.h"

void read_input(char **digits, char **dictionary, int argc, char **argv)
{
        if (argc < 2 || argc > 3)
    {
        ft_putstr("error");
        exit (1) ;
    }

    if (argc == 2)
    {
        read_input_digits(digits, argv[1]);
    }
    else
    {
        read_input_dict(dictionary, argv[1]);
        read_input_digits(digits, argv[2]);
    }
}

#include "functions.h"

void read_input_dict(char **dictionary, char *argv)
{
    *dictionary = malloc ((ft_strlen(argv)+1) * sizeof(char));
    *dictionary = ft_strcpy(*dictionary, argv);
    //ft_putstr(*dictionary);
}

#include "functions.h"

void read_input_digits(char **digits, char *argv)
    {
        *digits = malloc((ft_strlen(argv)+1) * sizeof(char));
        *digits = ft_strcpy(*digits, argv);
        check_only_digits(*digits);
        store_user_numbers(*digits);
        //ft_putstr(*digits);
        //ft_putchar('\n');
    }

#include "functions.h"
#include "globals.h"

void store_user_numbers(char *digits)
{
    int count_blocks, count_digits, user_number;
    char *read_digits;

    read_digits = digits;
    count_digits = 0;
    count_blocks = 0;
    g_blocks = parse_blocks(digits);
    g_user_numbers = malloc(sizeof(parsed_num) * g_blocks);
    str_end(&read_digits);
    while (count_blocks < g_blocks)
    {
        g_user_numbers[count_blocks].exponent = count_blocks;
        g_user_numbers[count_blocks].units = parse_number(&read_digits, digits);
        count_blocks++;
    }
}

#include "functions.h"

void str_end(char **str)
{
    while(**str != '\0')
    {
        (*str)++;
    }
    (*str)--;
}

#ifndef TYPES_H
#define TYPES_H

typedef struct{
    int exponent;
    int units;
}parsed_num;

typedef struct{
    parsed_num number;
    char *name;
}dict_num;

#endif     

问题根源与修复方案

根源

段错误的直接原因是**dictionary指针未初始化就被传入load_dict函数**:
当程序以argc=2运行时(仅传入数字参数),read_input只会调用read_input_digits,此时main中的dictionary是未初始化的野指针。调用load_dict(dictionary)时,函数内部执行ft_strlen(dict)会访问非法内存,触发段错误。

修复方案

  1. 初始化指针:在main中先将指针初始化为NULL:
char *digits = NULL; 
char *dictionary = NULL;
  1. 处理argc=2的情况:在read_input中为argc=2的场景设置默认字典路径:
void read_input(char **digits, char **dictionary, int argc, char **argv)
{
    if (argc < 2 || argc > 3)
    {
        ft_putstr("error");
        exit (1) ;
    }

    if (argc == 2)
    {
        read_input_digits(digits, argv[1]);
        // 分配内存并设置默认字典路径
        *dictionary = malloc(ft_strlen("numbers.dict") + 1);
        if (*dictionary == NULL)
        {
            ft_putstr("error");
            exit(1);
        }
        ft_strcpy(*dictionary, "numbers.dict");
    }
    else
    {
        read_input_dict(dictionary, argv[1]);
        read_input_digits(digits, argv[2]);
    }
}
  1. 修复内存泄漏:read_input_dict和read_input_digits中存在内存泄漏(malloc后直接覆盖指针),修正如下:
void read_input_dict(char **dictionary, char *argv)
{
    int len = ft_strlen(argv);
    *dictionary = malloc((len + 1) * sizeof(char));
    if (*dictionary == NULL)
    {
        ft_putstr("error");
        exit(1);
    }
    ft_strcpy(*dictionary, argv);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 20:49:50