当我运行后验函数时,函数中间出现段错误

问题描述 投票:0回答:1

我的练习是用英语编写一个字符串解析器,将其解析为数字的书面形式,我可以毫无问题地获取数字,并将其以我们选择存储的格式解析后写回。但是,如果在打印之后我调用另一个函数,我会在打印过程中出现段错误。 这个

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     
c parsing segmentation-fault global-variables
1个回答
0
投票

printf
和其余的标准 i/o 函数是 buffered,这意味着当您调用它们时,它们实际上并不会立即打印所有内容。由于 I/O 操作非常慢,它们会将内容累积到内部缓冲区中,并且只有在有足够的数据时(或者当您明确告诉它们时)才打印。 我不知道这是否正是你的问题(你调用Linux特定的函数,而我在Windows上),但你可以尝试两件事:

  • printf(...)
    转换为
    fprintf(stderr, ...)
    ,因为 stderr 没有缓冲。
  • fflush(stdout)
    之后调用
    printf
    (这是你明确告诉它立即打印的方式)

如果我的假设是正确的,这两件事中的任何一个都应该使程序在实际崩溃的地方看起来崩溃,所以在

ft_strlen
中。

附注我不认为编写自己的标准函数版本是愚蠢的,除非您很着急。这是一个很好的练习,即使你的功能变得更糟。我记得这个缓冲的主要原因是,上次我编写自己的打印函数来单独打印每个字符时,我体验到了它令人难以置信的缓慢 - 打印一条简单的消息比整个软件渲染例程慢!经常重写东西,我的朋友。不一定要重新发明轮子,而是要理解为什么正方形不起作用。

© www.soinside.com 2019 - 2024. All rights reserved.