Bug na hora de imprimir.

1. Bug na hora de imprimir.

Willyam de Paiva Cortez
WillyamCortez

(usa Debian)

Enviado em 15/09/2021 - 17:51h

Alguém sabe me dizer por que isso ta acontecendo ? a Placa está puxando o modelo pro lado quando vai imprimir.

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

typedef struct { /*//definindo a estrutura*/
char marca[30];
char ano[7];
char placa[7];
char modelo[20];
} ficha_cadastral;

void sair(){
printf("\n\t****Saindo da listagem de veículos****\n");
}

int main() {
int i,j;
int continuar=1;
ficha_cadastral veiculos[4];
do{
printf("1: Inserir um veículo:\n");
printf("2: Veículos por modelo:\n");
printf("3: Listar veículos:\n");
printf("4: Filtrar veículos por ano de fabricação\n");
printf("5: Digitar o ano de fabricação:\n");
printf("0: Para sair :\n");
scanf("%d", &continuar);
getchar();
switch(continuar){
case 1:
for(i=1; i<4; i++){
printf("\nDigite a marca do veículo:\n");
scanf("%s", &*veiculos[i].marca);

printf("\nDigite o ano do veículo:\n");
scanf("%s", &*veiculos[i].ano);

printf("\nDigite a placa do veículo:(No modelo XXX-YYYY)\n");
scanf("%s", &*veiculos[i].placa);

printf("\nDigite o modelo do veículo:\n");
scanf("%s", &*veiculos[i].modelo);

}
getchar();
break;
case 2:
printf("\nVeículos em ordem de modelo:\n");
for(i=1; i<4; i++){
for(j=i+1;j<4;j++){
if(strcoll(veiculos[i].modelo , veiculos[j].modelo) > 0 ){
veiculos[0]=veiculos[i];
veiculos[i]=veiculos[j];
veiculos[j]=veiculos[0];
}
}
}
for(i=1;i<4;i++){
printf("\nMarca: %s \nAno: %s \nPlaca: %s \nModelo: %s\t\n",veiculos[i].marca,veiculos[i].ano,veiculos[i].placa,veiculos[i].modelo);
}
break;
case 3:
for(i=1;i<4;i++){
printf("Veículos: \n");
for(i=1;i<4;i++){
for(i=j+1;j<4;j++){
if(strcoll(veiculos[i].marca , veiculos[j].marca)>0){
veiculos[0]=veiculos[i];
veiculos[i]=veiculos[j];
veiculos[j]=veiculos[0];
}
}
}
for(i=1;i<4;i++){
printf("\nMarca: %s \n",veiculos[i].marca);
printf("\nAno: %s \n",veiculos[i].ano);
printf("\nPlaca: %s \n",veiculos[i].placa);
printf("\nModelo: %s \n",veiculos[i].modelo);
}
break;
case 4:
for(i=4;i<4;i++){
printf("Veículos por Ano: \n");
for(i=1;i<4;i++){
for(i=j+1;j<4;j++){
if(strcoll(veiculos[i].ano, veiculos[j].ano)>0){
veiculos[0]=veiculos[i];
veiculos[i]=veiculos[j];
veiculos[j]=veiculos[0];
}
}
}
}
for(i=1;i<4;i++){
printf("\nMarca:%s \n",veiculos[i].marca);
printf("\nAno: %s \n",veiculos[i].ano);
printf("\nPlaca: %s \n",veiculos[i].placa);
printf("\nModelo: %s \n",veiculos[i].modelo);

}
break;
case 5:
break;
case 0:
sair();
break;
default:
printf("Essa opção não existe\n");
}
}
}while(continuar);
return 0;
}




  


2. Re: Bug na hora de imprimir.

Paulo
paulo1205

(usa Ubuntu)

Enviado em 16/09/2021 - 09:47h

O bug não está na hora de imprimir, mas sim na hora de ler e armazenar os dados.

Toda string em C precisa ter um byte nulo (caráter '\0') indicando onde a string termina. Para tanto, o vetor no qual a string é armazenada tem de prever espaço para a existência desse byte nulo.

No seu caso, você alocou 7 bytes para o campo placa. Quando você lê os sete caracteres da placa, a função scanf() preenche os sets caracteres que você digitou e acrescenta um byte nulo na posição seguinte da memória, como se fosse um oitavo elemento do vetor placa. Só que, como esse vetor só tem espaço para sete elementos, esse oitavo byte acaba residindo na primeira posição de memória do próximo campo da estrutura ficha_cadastral, isto é, como primeiro elemento do campo modelo.

Esse é o clássico problema de buffer overrun (exceder a capacidade de armazenamento alocada), agravada pelo fato de que você não está criticando o que o usuário digita (se, em vez de sete caracteres da placa ele digitasse centenas de caracteres antes de apertar a tecla Enter, o programa iria sobrescrever muito mais coisas na memória). Todas as leituras de strings que você faz no seu programa por meio de scanf("%s", ...) estão sujeitas a buffer overrun.

Mas, voltando ao seu caso, em que o buffer overrun excedeu apenas um byte, como você lê o modelo imediatamente depois de ler a placa, aquele byte nulo que tinha sido gravado num lugar impróprio é sobrescrito pelo primeiro caráter do modelo que você digitou. Quando você manda imprimir a placa sem especificar o comprimento máximo que uma placa pode ter, a função printf() vai imprimindo caracteres até encontrar o byte que sinaliza o fim da string. Como tal byte que fora armazenado na posição errada na hora da leitura da placa acabou sendo sobrescrito, a impressão continua pelos caracteres do campo seguinte até que, com um pouco de sorte, encontre o byte nulo do campo modelo.

Como corrigir?

1) Uma coisa da qual você nunca deveria fugir seria garantir que todas as leituras estão sendo feitas de maneira segura, colocando, no mínimo, limitações na quantidade máxima de caracteres que serão transferidos para os respectivos destinos. Melhor ainda seria validar se as informações estão válida (por exemplo, se todas as placas estão no formado de “três letras seguidas por um algarismo, um alfanumérico (para aceitar tanto placas brasileiras antigas, em que deveria ser algarismo, quanto o formato do Mercosul, que usa letra) e mais dois algarismos”).

2) Duas soluções alternativas:

2.a) Solução fácil: reservar espaço dentro de cada campo da estrutura para guardar todos os terminadores de strings, além dos dados (no caso do campo placa, por exemplo, você teria de ter oito elementos, sendo sete para os dados e um para o terminador). A vantagem é ser simples, não precisando permitindo-lhe usar funções comuns de manipulação de strings. A desvantagem é gastar mais espaço de memória ou disco para armazenar conteúdo que não representa nenhum dado útil.

2.b) Solução (supostamente) melhor: levar em consideração o tamanho de cada campo em cada operação de leitura, impressão ou manipulação de conteúdo, de modo a não depender necessariamente dos bytes terminadores para saber se uma string chegou ao final. Nesse caso, teria de trocar, por exemplo, “strcmp(reg.placa, alguma_placa)” por “strncmp(reg.placa, alguma_placa, sizeof reg.placa)”, “printf("%s", reg.modelo)” por “printf("%.*s", (int)sizeof reg.modelo, reg.modelo)” etc. (no caso da leitura, a solução vai ser mais complicada, mas isso já foi dito acima, na sugestão (1)). A vantagem desta abordagem é economizar espaço de armazenamento, evitando ter de guardar marcadores que não acescentam informação útil, e a desvantagem é ter de ter código mais elaborado para compensar a falta desses marcadores.


Há outros problemas no seu programa, mas não vou entrar em pormenores agora, pois tenho de voltar ao trabalho. Caso queira, posso comentar mais tarde.


... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts