How to store any string in C?

Asked

Viewed 3,514 times

8

How do I store a string (input) without knowing the size of this string, for example:

#include<stdio.h>
int main (){
char nome[];     /* a array não tem tamanho determinado porque o input ainda
                  não foi dado */
printf("Qual o seu nome?\n");
scanf("%c", &nome[]);    /* não sei como colocar o input na array */
return 0;
}

3 answers

8


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.

2

By the way, if we are using the usual gnu cc (gcc) -- in Linux and available for everything that is platform -- or any compatible implementation with POSIX 2013, we can use "%ms" to read by allocating the required space:

#include <stdio.h>

int main(){
  char *nome;
  scanf("%m[^\n]",&nome);   // lê linha, alocando o espaço necessário
  printf("bom dia, %s\n", nome);
  //   free(nome);
  return 0;
}

\Thanks{@hugomg}

  • 1

    The scanf manual recommends using %m instead of %a.

  • @hugomg, thanks (corrected): I’m always deactualized! by the way this works outside of gcc?

1

Even though it is not a good practice in my view in this language, here is a link with the same doubt Link, you can make a dynamite allocation in memory so that it changes according to the size of your string.

Remembering that Char has a maximum size that can be inserted.

I hope I’ve helped!

  • In fact char has a maximum size of 1 byte per specification. Only allocating memory dynamically does not solve the problem.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.