1

I'm having segmentation fault problem with this structure. I try to use strcpy to copy the char value to the list struct but not worked.


    #include <stdio.h>
    #include <stdlib.h>
    #include <malloc.h>
    #include <string.h>

    typedef struct Elemento_FILA{
    // int cod_cliente, consumo, dia_venc, mes_venc, ano_venc;
    // float preco_un,valor_total;
    char nome_cliente[40];
    struct Elemento_FILA *proximo;
    } Elemento_Fila;

    typedef struct Fila{
    struct Elemento_FILA *inicio; 
    struct Elemento_FILA *fim; 
    } Fila;
    int escolha; 


    Fila* Criar_Fila(){

    Fila *f = (Fila*) malloc(sizeof(Fila));
    if(!f)
    exit(1);
    else {
    f->inicio = NULL; 
    f->fim = NULL; 
    }
    return f;
    }


    int Fila_Vazia(Fila *f){
    if(f==NULL) return 1; 
    if(f->inicio==NULL) return 1; 
    else return 0;
    }

    int Ler_Cod(){
    int cod;
    printf (" Digite o código para o cliente: ");
    scanf("%i",&cod);
    return cod;
    }

    char* Ler_Nome() {
    char* nome_cliente = malloc(40*sizeof(char));
    printf(" Digite o nome do cliente: ");
    scanf("%s", &nome_cliente);
    return nome_cliente;
    }

    int Ler_Consumo(){
    int consumo;
    printf (" Digite o consumo para o cliente: ");
    scanf("%i",&consumo);
    return consumo;
    }


    Elemento_Fila* Alocar(const char* nome){

    Elemento_Fila *no_fila = (Elemento_Fila*)malloc(sizeof(Elemento_Fila));

    if(!no_fila)
    exit(1);
    else{

    strcpy(no_fila->nome_cliente,nome); 


    return no_fila;
    }
    }

    void Enfileirar(Fila *f){
    Elemento_Fila *no_fila = Alocar(Ler_Nome());
    if(!no_fila) 
    exit(1);
    if(f->fim == NULL) 
    f->inicio = no_fila;
    else 
    f->fim->proximo = no_fila; 
    f->fim = no_fila; 
    }

    int Desenfileirar(Fila *f){

    if(Fila_Vazia(f)) return 0;

    Elemento_Fila *no_fila = f->inicio;

    f->inicio = f->inicio->proximo;

    if(f->inicio==NULL)
    f->fim = NULL;

    free(no_fila);
    return 1;
    }

    void Exibir_Fila(Fila *f){

    if(Fila_Vazia(f)){
    printf (" Fila Vazia!\n");
    printf ("\n Fila End. Inicio %p: ", f->inicio);
    printf ("\n Fila End. Fim %p: ", f->fim);
    return ;
    }

    Elemento_Fila *aux = f->inicio;
    printf ("\n Fila Atual: ");
    printf ("\n Fila End. Inicio %p: ", f->inicio);
    printf ("\n Fila End. Fim %p: ", f->fim);
    printf ("\n");

    while(aux!=NULL){
    printf ("\n\t  Nome: %s  \tEndereco: %p ==> %p", aux->nome_cliente, aux, aux->proximo);

    aux = aux->proximo;
    }
    printf ("\n");
    }

    void opcoes(int escolha, Fila *f){
    switch(escolha){
    case 1:
    Enfileirar(f);
    Exibir_Fila(f);
    break;
    case 2:
    Desenfileirar(f);
    Exibir_Fila(f);
    break;
    default:
    if (escolha!=0) printf (" Opção Inválida!\n");
    }
    }


    int menu(){
    printf ("\n Opções da Fila;\n");
    printf (" 0 Sair;\n");
    printf (" 1 Inserir na Fila;\n");
    printf (" 2 Retirar da Fila;\n");
    printf (" Escolha: ");
    scanf("%i", &escolha);
    return escolha;
    }

    int main (void){

    Fila *f = Criar_Fila();
    do{
    escolha = menu();
    opcoes(escolha,f);
    }while(escolha);
    return 0;
    }

2 Answers2

1

you have several issues here but the most critical is what you doing here in the function Ler_Nome() below:

char Ler_Nome() {
  char nome_cliente[40];
  printf(" Digite o nome do cliente: ");
  scanf("%s", &nome_cliente);
  return nome_cliente;
}

Elemento_Fila *Alocar(const char *nome) {
    ....
    strcpy(no_fila->nome_cliente, nome);
}

you are returning a pointer to nome which is a local variable in function Ler_Nome(), in runtime when control reach the return all function local variables are released. you are returning a pointer to variable that not yours! hence the OS shout at you, by throwing segmentation fault !

And then you are trying to call strcpy on that release local variable (nome_client), in function Alocar(...) which lead to disaster ! even though, this is no the way things done in C you didnt even call the bad function Ler_Nome().

Keep in mind

  1. if you want to return pointer from function it must be allocated on the heap!
  2. if you want this pointer then you need to call the function to invoke it and get its return value (nome_client pointer in your case)
  3. Always check malloc() return value ! you didnt check pint integer pointer ! I dont know why you have allocated an integer pointer (or array of one integer), and you didnt use it at all in the function Alocar(...), and then you have exit the function without freeing it (by calling to free() function) ??!! this will cause to memory leaks in runtime when you try to call Alocar(...)
  4. Rule number 4: you need to make sure that all heap allocated buffers (that received by calling the *alloc() family) must be managed and freed properly!
Adam
  • 2,820
  • 1
  • 13
  • 33
1

This method:

char Ler_Nome() {
  char nome_cliente[40];
  printf(" Digite o nome do cliente: ");
  scanf("%s", &nome_cliente);
  return nome_cliente;
}

Is returning a local variable nome_cliente.

Since nome_cliente is allocated on the stack, when you return the object will dissappear.

This is a grave bug. Never do this.

If you need to return an array it must be allocated on the heap:

char* Ler_Nome() {
  char* nome_cliente= malloc(40*sizeof(char));
  printf(" Digite o nome do cliente: ");
  scanf("%s", &nome_cliente);
  return nome_cliente;
}

Note that its also probably good practice to create a destroyNome() function since the API responsible for creating should be responsible for its destruction as well.

AminM
  • 822
  • 4
  • 11
  • Trying to implement your function but had same error. – Guilherme Silva Jun 19 '20 at 06:36
  • you possibly have several bugs in your code. This was just one of them. – AminM Jun 19 '20 at 06:38
  • you are mixing up several concepts here.. If Enfileirar() is to add to the linked list its customary that it would recieve 2 things: the pointer to the queue, and the pointer to the data. You are calling functions to receive the data. And that's not great design. The queue should be more general purpose than that like: q = CreateQ(); Enfileirar(q, data); DestroyQ(q); The queue should not be the one making calls to create things. Better organization will make it easier to debug your code. C is a language that requires great discipline. – AminM Jun 19 '20 at 06:48
  • I'd also suggest inializing ALL members of your structs right after malloc(). Don't assume that malloc() will set everything to 0. That may work in DEBUG mode but no such guarantees in RELEASE. A neat trick is to use memset() right after verifying that the allocation was successful. – AminM Jun 19 '20 at 06:48
  • i just edited and post the full code , its not that big , if you can take a look and helps search for bugs... – Guilherme Silva Jun 19 '20 at 06:56
  • 1
    Thxx man i follow your advices and refactored the code and it works, just change the function Enfileirar to receive data instead a new function. – Guilherme Silva Jun 19 '20 at 22:28