Good evening, your code there are some errors, so the text will be a little long...
Prototypes of the functions
Start with the prototypes of its functions:
int menu ();
void ler (FILE*);
int gravar (FILE*);
int escrever_dados (FILE*);
Remove the spaces between the parentheses and their name, also decrease the space between the type of return with the name, so it is more organized:
int menu(void);
void ler(FILE*);
int gravar(FILE*);
int escrever_dados(FILE*);
Another problem is their arguments, note that you forgot to put the variable, you just put the type. The prototype needs to look like this:
int menu(void);
void ler(FILE *file);
int gravar(FILE *file);
int escrever_dados(FILE *file);
Now prototypes can use a pointer to files, before they could not because they were not declared.
Pointer declaration for this
In this part of the code you don’t need to use malloc:
FILE *file = (FILE*)malloc(sizeof(file));
When you do FILE *file;
the file pointer is already created. Create a pointer to the file using the malloc()
would only be useful if the pointer was encapsulated in another file, but as this is not the case then just do it:
FILE *file = NULL;
Leave the pointer equal to NULL
is not required, but this may prevent you from using pointers pointing to unknown places in memory... So recommend you always match the NULL
pointers not currently used.
Select variable
The variable select
is kind of useless in your code, because the return of the function menu()
can be used without problem on the switch:
switch(select = menu()) // Isso dá no mesmo
switch(menu()) // que isso
fopen()
It’s not necessarily a mistake, but the fopen()
returns NULL when it fails, but it’s probably the same thing in C, I’m not sure... But I think your code will look more elegant with:
if(file != NULL)
/* Você ainda pode otimizar espaço ao fazer isso */
if((file = fopen(arquivo,"r")) == NULL) return /* numero com erro */; /* E aqui pode encerrar a função/programa em caso de erro, pode usar um return para sair da função com erro */
/* Aqui será ativado em caso de sucesso */
Forgetting to close the file
At the end of the function ler()
you forget the fclose(nome_do_arquivo)
to close the file. Remember that in C the data does not go directly to the disk file but to the stream, the fclose
is to warn the program that all changes in that file have already ended and it can close and download the data there, if you do not do so then there are chances of losing the data...
You also forget the fclose
in function gravar()
... Example of what the fclose()
in your code:
fclose(file);
fflush(stdin)
A very common mistake is the use of fflush(stdin)
, Maybe this command is so popular because many of the Federal teachers recommend it, I don’t know why, but it happens a lot and I speak from experience... In short: fflush()
have the undefined behavior when the argument is stdin
, I mean, it might work, it might not work, or there could be other things... Even if it works on your PC I recommend not to use, this command is very poorly seen among programmers.
One solution to solve this problem that some recommend is the setbuf(stdin, NULL)
, but that command doesn’t work on every computer. I won’t go into too much detail, as questions about how to clean the buffer have already been discussed a lot. The solution I give you is this::
void limpar_buffer(void)
{
char lixo;
do
{
lixo = getchar();
}while(lixo != '\n');
}
I wrote it in a very didactic way for you to understand, but it is possible to compress this function. Use it whenever you’re sure there’s trash in the buffer.
Keyboard reading with gets or scanf("%s")
These functions do not serve to read strings from the keyboard, as they do not necessarily have a character limit to be read, that is, if the user writes something with 50 characters and the string is only 20 in size then 30 characters will be read and put somewhere in memory (probably in the following positions of its vector, that is, v[21], v[22], ..., v[30], consider that from v[21] they are not parts of its vector). This problem is called overflow, check it out later.
To solve the problem most recommend using the fgets(variavel_que_ficara_a_string, tamanho_da_string, stdin)
. Example of use:
char nome[20];
fgets(nome, 20, stdin);
This way you set a limit of 20 characters to be read
fgets problems with the clean buffer function that I recommended
I especially do not recommend using the fgets
, for some reasons, the main thing that really comes to the case is that it has a problem with the buffer.
Well, when the fgets
read less characters or the expected amount so it does not leave garbage in the buffer and this is great, but if the user type a larger amount then the characters that do not enter the array/string will be as memory junk. Test the code below to see:
char nome[5], n[5];
fgets(nome, 5, stdin);
fgets(n, 5, stdin);
printf("%s \n", nome);
printf("%s \n", n);
In the code above type names with less than 5 characters and note the output, then type a name with 6 or more characters and notice that the trash that will be assigned to the second fgets.
The first solution to solve this is to use the function of limpar_buffer()
that I recommended, but with that we have a problem. The problem is that the lmipar_buffer() function will open the keyboard input if the buffer is clean and this would cause a "pause" in the program, and that’s not what we want. Because it is not possible to predict whether fgets will leave garbage in the buffer then we cannot use the limar_buffer together with fgets.
One solution is to create the function itself to read a string:
void ler_string(char *nome, int tamanho)
{
char letra, i = 0;
do
{
letra = getchar();
if(letra != '\n' && i < tamanho - 1)
{
nome[i] = letra;
i++;
}
}while(letra != '\n');
nome[i] = '\0';
}
The above function can be compacted, but I wrote so as to make it easier to understand it. This function will never leave junk in the buffer independent of what the user type.
Problem using getchar to pause program
Many use the getchar()
as an alternative to the system("pause")
, is a great alternative if you want to pause to avoid closing the window when the program ends, but if used in the middle of the program the getchar()
can leave a trash in the buffer and bring an unexpected behavior. Example:
printf("Pressione enter para continuar... \n");
getchar();
printf("Digite um caractere: ");
scanf("%c", &n);
In the above program if the user type enter then fine, but if you type something like aofhdskajfe hit enter then the a will be "deleted" and the rest will look like garbage in the buffer, that is, the scanf would read the "o" and that is not what we want. out that the trash can be read in a string without us waiting. A simple solution to this is to use the function limpar_buffer()
to pause the screen, it always pauses the screen when there is no garbage in the buffer (so it does not get along with fgets as I mentioned).
The code above would look like this:
printf("Pressione enter para continuar... \n");
limpar_buffer();
printf("Digite um caractere: ");
scanf("%c", &n);
These are the main problems I found in your code, there may be more, I don’t know. Make the changes and see. I didn’t test with the changes I mentioned because I spent a lot of time analyzing your code and writing this answer and so I’m a little tired. But I hope I have helped in something. In case there is still some problem then let me know.
I think there are many problems in your code. I start with: what is the meaning you want with
FILE *file = (FILE*)malloc(sizeof(file));
?– anonimo