In your example just put 1 because you are only reading 1 character through the %c
. So I didn’t even need the array. But there’s a solution if you want string. There are other syntax errors.
The basic technique is to create a buffer (the variable nome
in your case) to the largest possible name you want to accept and still put a restrict of how many characters can come in this buffer (use scanf()
pure is a tremendous security breach).
Has a question as to why it is necessary to create a buffer of a certain size.
In general this is not problematic, unless you need to allocate a very large space, which is highly unlikely to scanf()
.
If it is very important to allocate the required size at once, you may ask before which size to allocate, then just use the variable to create the array:
int tamanho = 0;
scanf("%d", &tamanho);
char nome[tamanho];
There’s only one small detail, how this is going to be allocated to the stack and it’s not that big, if this size is too big it’s going to be a problem. In exercise goes beauty. In real application nor is it done so.
In fact the most used technique is not even to use array in the stack, is rather a dynamic allocation in the heap through malloc()
. Still it is necessary to know the size beforehand.
If it really is necessary to allocate memory as needed to save memory, the solution usually makes relocations. Many programmers create a general function to manage this. What is done is to read the characters and go allocating in one buffer, when it fills creates another buffer bigger and copies what was in the previous one and continues from there. This can be done even increasing of character by character. Obviously the performance is not the best, but for a keyboard typing is irrelevant. There is a technique of relocation (realloc()
) which avoids manual copying and in some cases even full copying of content.
A code that does this would be so (don’t consider it ready for use in production, I wouldn’t even do it for real, but it’s easy to understand):
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int size = 0;
char *nome = malloc(2); //espaço extra para 1 caractere mais o terminador de string \0
while (1) {
if ((scanf("%c", &nome[size])) == 1) {
nome[size + 1] = '\0'; //coloca o terminador
if (nome[size] == '\n') {
break;
}
nome = realloc(nome, ++size);
if (nome == NULL) {
printf("Ocorreu algum problema");
break;
}
} else {
printf("Ocorreu algum problema");
break;
}
}
printf("%s", nome);
free(nome);
}
Behold working in the ideone. And in the repl it.. Also put on the Github for future reference.
I would start with the size of 64 bytes (cache line from the typical processor, I find a dirty object in the heap with smaller size, although it makes sense in some cases) and would double the size each time the capacity was reached, so the reallocation would have logarithmic complexity and occur much less often. Including because the space occupied in the heap has a overhead of book keeping 4 to 16 bytes typically, so it doesn’t pay to be saving a few bytes. Doing so will have memory waste most of the time, but ends up being better for performance and in some cases much relocation causes memory fragmentation that can even waste more memory still. The least I would use is 8 bytes because usually you can’t allocate smaller portions than this (or take a number according to the one used in context by the platform or library).
If it was a ready function it would be good to have a parameter for the consumer to start with the size he thinks best (even giving him a chance to make the wrong choice) and have a maximum size that allows to achieve, including the last relocation (if the first is no longer the last one) would use that number.
Anyway, you can optimize this code much more.
In that reply from the same author has a suggestion on how to improve the reallocation described here, with logarithmic execution complexity
– Jefferson Quesado