Ir ao conteúdo

Posts recomendados

Postado

Isolei uma parte de um codigo de um trabalho, e explicando do inicio, basicamente, tenho duas struct que tem dois campos de pointers de tipos em comuns (tm *), e sendo assim, não queria ter que fazer duas funcoes pra limpar a memória desse campo delas, queria fazer somente uma, fiz um algoritmo com a ideia de utilizar o cast para converter um ponteiro generico para o tipo da struct necessária e só depois limpar os campos, mas não funcionou, por curiosidade testei o mesmo codigo com um ponteiro sem ser da time.h, e deu certo, e se eu limpo até mesmo normalmente o tm *, tb da erro de execução, estou manipulando erroneamente a funcao localtime? Em depuracao mostra estar recebendo todos os valores da forma correta.

 

Edit: Só uma att, por localtime retornar um tm *, eu fiz dessa forma por imaginar que ele ja esta alocando um local na memória do tamanho de tm, e retorne somente seu endereco.

 

Codigo que não funciona: 

#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include <stdarg.h>
#include <time.h>

typedef struct lancamentoCaixa{
    
    time_t codigoCompra;
    int modoPagamento;
    float valor;
    float valorPago;
    float troco;
    struct tm*data;
    
}lancamentoCaixa;

typedef struct contaArec{
    int codigoCliente;
    time_t codigoCompra;
    int modoPagamento;
    int parcelas;
    float valorParc;
    float entrada;
    struct tm*dataAluga;
}contaArec;

void limpaData(int escolha, int quantidadeLanc, void *endereco){
    
        
    for(int i = 0; i<quantidadeLanc; i++){
        switch(escolha){

            case 1:
                free(((lancamentoCaixa *)endereco)[i].data);
                ((lancamentoCaixa *)endereco)[i].data = NULL;
                break;

            case 2:
                free(((contaArec *)endereco)[i].dataAluga);
                ((contaArec *)endereco)[i].dataAluga = NULL;
                break;
        }
    }
    
    
    
}

int main(){
    
    time_t seg;
    time(&seg);
    
    contaArec teste;
    lancamentoCaixa teste2;
    
    teste.dataAluga = localtime(&seg);
    teste2.data = localtime(&seg);
    //free(teste2.data); //caso descomentar essa linha, o erro começa a acontecer aqui
    limpaData(1, 1, &teste2);
}

Codigo que funciona: 

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include <stdarg.h>
#include <time.h>


typedef struct teste{
    
    char *nome;
}teste;

typedef struct testeee2{
    char *nome;
}testeee2;


int digText(FILE *f, char **text){
    int indice = 0;
    
    text[0] = malloc(sizeof(char));
    
    do{
        
        text[0][indice] = fgetc(f);
        
        if(text[0][indice]!='\n'){
            text[0] = realloc(text[0], sizeof(char)*(indice+1));
        }
        indice++;
    }while(text[0][indice-1] != '\n');
    text[0][indice-1] = '\0';
    return indice+1;
}

void limpaNome(int escolha, int quantidade, void *end){
    /*funcao recebe um endereco de uma struct teste ou testeeee2 por meio de um ponteiro generico, e converte ele pra forma adequada
     através do primeiro argumento da funcao, limpando assim adequadamente*/
    for(int i = 0; i<quantidade; i++){
        
        switch(escolha){
            
            case 1:
                free(((teste *)end)[i].nome);
                ((teste *)end)[i].nome = NULL;
                break;
            case 2:
                free(((testeee2 *)end)[i].nome);
                ((testeee2 *)end)[i].nome = NULL;
                break;
        }
    }
}
int main(){
    
    teste agora;
    testeee2 agoraggg;
    
    digText(stdin, &agora.nome);
    digText(stdin, &agoraggg.nome);
    printf("%s\n%s\n", agora.nome, agoraggg.nome);
    
    limpaNome(1, 1, &agora);
    
    
}

 

  • Curtir 1
Postado
Como te disse, forums como esse são mais favoráveis
a questões como a sua que o Stack Overflow

 

Sobre tm e localtime

 

"Isolei uma parte de um codigo de um trabalho, e explicando do inicio, basicamente, tenho duas struct que tem dois campos de pointers de tipos em comuns (tm *), e sendo assim, não queria ter que fazer duas funcoes pra limpar a memória desse campo delas, queria fazer somente uma, fiz um algoritmo com a ideia de utilizar o cast para converter um ponteiro generico para o tipo da struct necessária e só depois limpar os campos, mas não funcionou, por curiosidade testei o mesmo codigo com um ponteiro sem ser da time.h, e deu certo, e se eu limpo até mesmo normalmente o tm *, tb da erro de execução, estou manipulando erroneamente a funcao localtime?"


Sim, está manipulando errado. Porque tal preocupação em liberar memória que você não alocou? Nunca faça isso. Leia a documentação. Veja o que está escrito sobre isso, entre outras coisas:
 

Citação

A função localtime converte uma hora armazenada como um valor time_t e armazena o resultado em uma estrutura do tipo tm. O valor longsourceTime representa os segundos passados desde a meia-noite (00:00:00) de 1º de janeiro de 1970, no UTC. Geralmente, esse valor é obtido da função time.

 

 

Citação

As versões de 32 e de 64 bits de gmtime, mktime, mkgmtime e localtime usam uma estrutura simples tm por thread para a conversão. Cada chamada a uma dessas rotinas destrói o resultado da chamada anterior.

Isso em https://learn.microsoft.com/pt-br/cpp/c-runtime-library/reference/localtime-localtime32-localtime64?view=msvc-170 

 

Atente para a última sentença na citação.

 

3 horas atrás, mlkneutro disse:

Em depuracao mostra estar recebendo todos os valores da forma correta.

 

Edit: Só uma att, por localtime retornar um tm *, eu fiz dessa forma por imaginar que ele ja esta alocando um local na memória do tamanho de tm, e retorne somente seu endereco.

 

tm tem apenas 9 int. Mas sem ler a fonte de localtime você não tem como saber se essa área é estática ou se foi alocada ou como foi alocada. 

 

Ainda sobre o código que não funciona

 

typedef struct lancamentoCaixa{
    
    time_t codigoCompra;
    int modoPagamento;
    float valor;
    float valorPago;
    float troco;
    struct tm*data;
    
}lancamentoCaixa;

typedef struct contaArec{
    int codigoCliente;
    time_t codigoCompra;
    int modoPagamento;
    int parcelas;
    float valorParc;
    float entrada;
    struct tm*dataAluga;
}contaArec;

 

Escreva em torno dos dados.

 

E essas estruturas deveriam ser anônimas. Não há razão para repetir o nome toda vez.

A composição não está boa. Onde está o Caixa? Está claro que tem um container, um registro de lançamentos, mas o programa não tem isso. E aí vai claro como todo mundo precisar de mais um contador global para o total e outro para o limite. Veja os dois aqui em seu código
 

void limpaData(
    int escolha, int quantidadeLanc, void* endereco)
{
    for (int i = 0; i < quantidadeLanc; i++)
// ...

 

Não use nomes assim longos para campos que vai usar em expressões. Só vai ficar difícil de ler linhas super longas. 

 

Algo assim já seria mais conveniente

 

typedef struct
{
    time_t     cod;
    int        modo;
    float      valor;
    float      valorPago;
    float      troco;
    struct tm* data;

}   lancamentoCaixa;

typedef struct 
{
    int        cliente;
    time_t     cod;
    int        modo;
    int        n_parc;
    float      parc;
    float      entrada;
    struct tm* data;

} contaArec;

 

mas imagine a diferença de algo assim
 

#define MAX_LANC 20

typedef struct
{
    time_t     cod;
    int        modo;
    float      valor;
    float      valorPago;
    float      troco;
    struct tm* data;

}   Lanc; // Lancamento

typedef struct
{
    unsigned cap; // capacidade
    unsigned qtd; // quantos tem
    Lanc     lanc[MAX_LANC]; // os lancamentos

}   Caixa;

 

E entenda como isso faria sua vida mais simples. Uma hipotética limpaData() podia ser então
 

    void limpaData( Caixa* cx );

 

e você passa apenas o endereço de um Caixa e vai tudo junto. Esse é o conceito de encapsulamento em OOP.

 

Outro problema: 

 

em main()

 

int main()
{
    time_t seg;
    time(&seg);

    contaArec       teste;
    lancamentoCaixa teste2;

    teste.dataAluga = localtime(&seg);
    teste2.data     = localtime(&seg);
    // free(teste2.data); //caso descomentar essa linha, o
    // erro começa a acontecer aqui
    limpaData(1, 1, &teste2);
}

 

Acho que agora já sabe porque dá erro se chamar free() em uma área que não foi alocada por malloc(). Mas quando chama limpaData está passando uma única estrutura. Não é um vetor. A primeira posição é 0 e não 1. Não pode usar índices na função, exceto o 0 por ter passado um endereço afinal. Coisas como essas linhas

 

            case 1:
                free(((lancamentoCaixa*)endereco)[i].data);
                ((lancamentoCaixa*)endereco)[i].data = NULL;
                break;

 

estão bem erradas:

  • Não pode chamar free() para essa área
  • não pode usar o índice 'i' porque não é um vetor

Sobre o código que "funciona"

 

Está bem errado também.

 

Use nomes melhores... Provavelmente teste e testeee2 não são assim boas escolhas.

 

typedef struct teste
{
    char* nome;
} teste;

typedef struct testeee2
{
    char* nome;
} testeee2;

 

Em digText():

 

int digText(FILE* f, char** text)
{
    int indice = 0;

    text[0] = malloc(sizeof(char));

    do {
        text[0][indice] = fgetc(f);

        if (text[0][indice] != '\n')
        {
            text[0] = realloc(
                text[0], sizeof(char) * (indice + 1));
        }
        indice++;
    } while (text[0][indice - 1] != '\n');
    text[0][indice - 1] = '\0';
    return indice + 1;
}

 

Todo programa em C --- ou C++ ou java ou Python ou C# ou sei lá --- recebe na inicialização um vetor de strings. O protótipo de main em C é

 

    int main( int argc, char** argv);

 

Um char** por si só é um desastre. Não deve usar assim sózinho. Em sua função text é char** mas não dá pra saber só de olhar para ele o que tem dentro. Entenda o caso de main e porque essas coisas vem aos pares. Cada par de asteriscos precisa de um contador para poder reconstruir a coisa. Um arquivo CSV pode ser descrito como tipo char ** **. Um workbook do excel pode ser acessado como char ** ** **. Sim, 6 asteriscos. Então para tirar algo de dentro disso precisa de 2 valores para o CSV e 3 para as planilhas.

 

E no seu caso só usa o índice zero. Porque não usou então char* e retornou o ponteiro?

 

E está alocando memória byte a byte chamando realloc(). E se está lendo streams como stdin sabe que existem buffers e que a leitura não é letra a letra?

 

Ao que parece quer ler strings a partir do teclado. Então deve montar um vetor de ponteiros exaamente como o sistema faz a cada vez que roda seu programa, e retornar DUAS coisas: o vetor e o número de strings.

  • Curtir 2
Postado

O motivo de usar dupla referencia esta explicado nesse codigo, o endereco com ponteiro unico não volta pro ponteiro da funcao que chamou, e é aquele ponteiro que precisa receber o endereco da alocação dinamica da string, claro que eu poderia retornar um ponteiro no fim da execucao, mas eu perderia o poder de retornar  a quantidade de letras, coisa que preciso no programa.


 

int digText(char *text, FILE *f){
    
    text = malloc(sizeof(char));
    int indice = 0;
    
    do{
        
        text = fgetc(f);
        
        if(text[indice]!='\n'){
            text = realloc(text, sizeof(char)*(indice+1));
        }
        indice++;
    }while(text[indice-1]!='\n');
    return indice+1;
}

e contasArec não é diretamente ligado ao caixa, é uma struct de um arquivo que nas especificacoes do trabalho tera que ficar separado.

 

 

Postado

@mlkneutro eu te falei pra postar o enunciado.... Sem isso alguém que queira ajudar só pode estimar o que está tentando escrever.

 

Como expliquei essa composição dos dados é ruim. E mostrei porque e um exemplo. Nada tem a ver com o enunciado. TODOS esses exercicíos para inunciantes giram em torno de simples containers. Aqui é de lançamentos. O exercício seguinte é de playlist, tem o de vagas no estacionamento, o de tickets, o de launos, o de tickets, o da fila. Todos iguais.

A composição é aquela que te mostrei. Implemente e veja como tudo fica mais simples.

 

Sobre char**

 

Te mostrei 3 exemplos. um deles presente em TODO programa C. Eu não posso estar errado. Isso vem dos anos 60.

 

E  te expliquei o que está errado: o que é text? é char**. Isso quer dizer o que?

  • *text é char**
  • **text é uma letrinha

Só isso. E é muito pouco para o programa. Como seria pouco para o seu programa em C. Por isso existe argc: argv é insuficiente. Dennis Ritchie era um gênio. Melhor acreditar nele e no pessoal da Bell Labs.

 

 

 

2 horas atrás, mlkneutro disse:

o endereco com ponteiro unico não volta pro ponteiro da funcao que chamou

 

Não volta porque você não retornou o endereço. Isso se chamaria composição. Ou encapsulamento.

Postado
1 hora atrás, arfneto disse:
  • *text é char**
  • **text é uma letrinha

 

  • *text é char*
  • **text é uma letrinha

Se 

 

      char**    text = NULL;

 

Digitei errado no post acima e não dá pra corrigir.  Desculpe.

 

3 horas atrás, mlkneutro disse:

O motivo de usar dupla referencia esta explicado nesse codigo, o endereco com ponteiro unico não volta pro ponteiro da funcao que chamou, e é aquele ponteiro que precisa receber o endereco da alocação dinamica da string, claro que eu poderia retornar um ponteiro no fim da execucao,

 

Sim, está errado como escreveu. Não é o motivo. Apenas o uso.

 

Corrigiu os outros erros?

Entendeu porque não pode usar free() em  tm?

Entendeu porque não pode usar índices naquela função?

Entendeu que alocar byte a byte e usar realloc() para  cada letra lida não deve ser uma boa ideia? 

Entendeu que se está usando apenas text[0] não há sentido em declarar text como char**?

 

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...