提问人:Fernando Loula 提问时间:9/3/2023 最后编辑:bartekczrnFernando Loula 更新时间:9/5/2023 访问量:48
当我运行后验函数时,函数中间的 Segfault
Segfault in the middle of a function when I run a posterior function
问:
我的练习是将字符串的解析器写成英文数字的书面形式,我可以毫无问题地得到这个数字,并以我们选择存储的格式将其写回解析。但是,如果在打印后我调用另一个函数,则在打印过程中会出现段错误。 这
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%
这
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
答:
2赞
NicknEma
9/5/2023
#1
printf
其余的标准 I/O 函数是缓冲的,这意味着当您调用它们时,它们实际上不会立即打印所有内容。由于 I/O 操作非常慢,因此它们会将内容累积到内部缓冲区中,并且仅在它们有足够的数据(或明确告诉它们时)才打印。
我不知道这是否完全是你的问题(你调用特定于 Linux 的函数而我在 Windows 上),但你可以尝试两件事:
- 转换为 ,因为 stderr 未缓冲。
printf(...)
fprintf(stderr, ...)
- 之后调用(这是您明确告诉它立即打印的方式)
fflush(stdout)
printf
如果我的假设是正确的,那么这两件事中的任何一件都应该使程序在实际崩溃的地方崩溃,所以在.ft_strlen
P.S. 我不认为编写自己的标准函数版本是愚蠢的,除非你很着急。这是一个很好的练习,即使他们的功能变得更糟。我记得这个缓冲功能的主要原因是,上次我编写自己的打印函数来单独打印每个字符时,我体验到了它令人难以置信的缓慢 - 打印一条简单的消息比整个软件渲染例程慢!经常重写东西,我的朋友。不一定是要重新发明轮子,而是要理解为什么正方形不起作用。
评论
0赞
Fernando Loula
10/23/2023
这个答案真的很神奇,也帮助我理解了我陷入的那种问题。非常感谢,真的很有帮助!
评论
#include "functions.h"
.c
#include "functions.h"
#include
-fsanitize=address
char_to_digit()
free_mem()
ft_openfile()
42
42