调用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)会访问非法内存,触发段错误。
修复方案
- 初始化指针:在
main中先将指针初始化为NULL:
char *digits = NULL; char *dictionary = NULL;
- 处理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]); } }
- 修复内存泄漏:
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
相关产品推荐
相关产品推荐

