Colo allocate a memory based on the size the user typed

Asked

Viewed 540 times

5

How can I get it right after the user enters a string the program counts the number x of characters of this and allocate X bytes to it?

I am not able to do it, I tried for example to make after the user type the string, this:

ponteiro = (char *) malloc (strlen(string));

In the above code, the user giving an input, for example, of the type: ABCDEF, would cause strlen to count 6 characters, thus allocating to the string 6 bytes.

But it goes wrong, since the memory allocation would be happening later, so before the string was 'picked up' there would be no bytes allocated to store it.
Does anyone know how to fix it?

  • How is the user typing? Enter your code. Maybe your problem is somewhere else. But I can already say that you will have to allocate before receiving the information.

  • bigdown, at the moment the code looks like this: http://codepad.org/oqBIJKVG, but what I want is that the program does not ask how many bytes the user will use, but that the program after the user type the string, use strlen and calculate the number of characters typed and allocate them. Got it?

  • @Leviivanovsk For these and other reasons (object orientation, for example) I chose C++. And it gives many better results on Google. Take a look!

  • @Leviivanovsk Take a look at [tour]. You can accept an answer if it solved your problem. You can vote on all the posts on the site as well. Did any help you more? You need something to be improved?

  • boot malloc(sizeof(string)), this returns the size occupied in memory by the string variable

3 answers

3

There are not many options. Basically you either allocate a sufficient amount for what you need or ask how much you want to allocate.

The second option really is terrible. From the usability point of view it doesn’t make any sense.

The first option has the disadvantage of possibly allocating more memory than actually needed. But who cares. This is no longer a problem on any kind of device unless you want to input really long text, but you wouldn’t do it simply anyway, in a long text you would have a data structure to manage it.

One might think that there is also the disadvantage of imposing a ceiling. But this is an advantage. Letting a user what is the maximum limit of text to type is the last thing the program should do. Again, if you need something more complex, you’ll need a more complex program.

So the solution is to do this:

#include <stdio.h>
#include <stdlib.h>
int main(){
    char *ponteiro = malloc(100); //um caractere será ocupado pelo terminador \0
    printf("String: ");
    scanf("%99s", ponteiro); //permite digitar um caractere a menos que o alocado 
    free(ponteiro);
    return 0;
}

Behold working in the ideone. And in the repl it.. Also put on the Github for future reference.

Now responses have appeared that show creative algorithms but that probably will be Overkill. My solution wastes memory, the others presented waste allocation time and in the commentary appeared one that wastes or two but in moderate quantities.

Have you noticed that there is no free lunch? You have to decide what you want to waste. In a simple example any can be wasted smoothly. I would use the occam’s razor and would keep the simplest. If I preferred the most complicated I would have posted it.

I could use an optimized version and better handled in more complex problems where I really was having memory problems and didn’t know the size of what I need in data input. I don’t have any of these problems ever so I never worried about it. I guess you shouldn’t either.

  • "Leibniz (1646-1716), Kant (1724-1804), Karl Menger (20th century) also disagreed with Occam’s razor. Leibniz stated that "the variety of beings cannot be diminished". Menger formulated the law against avarice, according to which "entities cannot be reduced to the point of inadequacy", and "it is useless to do with little that requires more"... Obviously none of these statements really contradict the sense of Occam’s Razor, but rather serve as a warning against overzeal in the application of the principle. The superfluous must be eliminated, but only that." hehehe.

3

There is a way to do what you want, but the performance of the code is questionable depending on the situation.

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

#define ALLOCATION_STEP 5

int main(void)
{
    int mem_left = ALLOCATION_STEP;
    int mem_size = mem_left + 1;
    int length = 0;
    int realloc_cnt = 0;
    char *buff = (char *)malloc(mem_left);
    char c = 0;
    while((c = getchar()) != '\n') {
        if(mem_left == 0) { // precisamos de mais memoria
            char *tmp = (char *)realloc(buff,mem_size + ALLOCATION_STEP);
            if(tmp == NULL) {
                printf("Falha na aquisicao de memoria!\n");
                free(buff);
                return -1;
            }
            buff = tmp;
            mem_left = ALLOCATION_STEP;
            mem_size += mem_left;
            ++realloc_cnt;
        }
        buff[length++] = c;
        --mem_left;
    }

    buff[length] = '\0'; // fecha a string

    printf("Tamanho: %d\n",length);
    printf("Memoria: %d\n",mem_size);
    printf("Padding: %d\n",mem_size - (length+1));
    printf("Realocacoes: %d\n",realloc_cnt);
    printf("String: %s\n",buff);

    free(buff);
    buff = NULL;

    return 0;
}

The above code allocates an initial amount of memory given by the value of ALLOCATION_STEP, then it starts reading the input stream until it finds a line break \n, throughout the process it copies the characters from the stream to the variable buff, if the remaining amount of memory indicated by mem_left come to 0 he realoca more ALLOCATION_STEP bytes of memory to continue the process until the end or until an allocation error occurs.

The problem is: A ALLOCATION_STEP too low can cause many relocations to occur making the performance of code questionable, there is also misuse of function realloc that can cause problems.

  • 1

    Instead of increasing the buffer size by 5 by 5, multiply the buffer size by a constant at each step (for example, double the buffer size at each allocation). Thus the amortized performance becomes linear instead of quadratic.

  • 1

    @hugomg Yes, it is a valid alternative, my code is just a basis of how to do what the OP wants, so I put this amount in a #define to symbolize that it can be increased to suit the situation and improve performance or also change the amount as the buffer grows.

  • 1

    I find the answer valid and I think of how much it matters if you think about doing the right thing. If it is to do "wrong", let it be 1 in 1 :) of course 5 in 5 is a little better, depending on case 10 in 10 or 50 in 50. Even better if it is geometrically progressive. But then we come to the conclusion that the right thing is to establish a maximum size than all input should have anyway and allocate it. Solves everything.

  • Yes @bigown, I commented on this in the other answer, your answer is the most sensible for accusing working with fixed sizes, posted this code to expand the options of OP, and explained that should-balance between the amount of relocations and their size according to your need, avoiding loss of performance or leftover memory.

  • @Cahe: it wasn’t a question of being configurable via define. Changing the step of your arithmetic progression will improve the time by a constant factor while using a geometric progression results in a better asymptotic complexity.

2

Simple: the same way C++ does with std::string. Leaves input buffer, reads from Chunk in Chunk and allocate more memory as needed.

Uses the following code:

char *getln()
{
    char *linha = NULL, *tmp = NULL;
    size_t tamanho = 0, index = 0;
    int ch = EOF;

    while (ch) {
        ch = getc(stdin);

        /* Checamos se devemos parar. */
        if (ch == EOF || ch == '\n')
            ch = 0;

        /* Checamos se devemos expandir. */
        if (tamanho <= index) {
            tamanho += CHUNK;
            tmp = realloc(linha, tamanho);
            if (!tmp) {
                free(linha);
                linha = NULL;
                break;
            }
             linha = tmp;
        }

        /* Finalmente adicionamos o caractere */
        linha[index++] = ch;
    }

    return linha;
}

Remembering that CHUNK is a value appropriate to you. The flawless way is #define CHUNK 1. The method can change the results of time (input much longer).

  • @Rinzler If it wasn’t good practice, C++ wouldn’t have implemented it in STL!

  • @Rinzler is not with object orientation that one makes a function related to string. I program in C++, I asked the related question (see nickname: iQChange) and asked why he was implementing a string in my personal libraries. Think about the relations of C and C++ and you will find the "little" reference for a procedural and object-oriented language. (The two use the same logical system, the two use Assembly, the two have the same type of standard variables, the two... )

  • @Lucashenrique do you have a source where specifically this is used in STL? This code presented is certainly not part of STL.

  • @bigown I have the STL quote on the link to the site cplusplus.com (link on Std::string). It’s interesting how they use object orientation to do the same in a way that can be implemented in C.

  • @Rinzler is fully aware of the reasons for the creation of C++ about C, his "father", and this I try to tell you. I did not know Simula; interesting.

  • The most sensible answer is @bigown which is to work with fixed sizes, even so I posted the same code 5 hours ago, I explained and discussed with @hugomg the problems of it and how it can be adapted to solve the question, incidentally define CHUNK to 1 is a bad idea.

  • @Cahe The funny thing is that other languages don’t have this problem and have adapted. How? Ah, and Chunk = 1 I only put in because I didn’t pay much attention to the code and I was afraid that if Chunk was != sizeof(char) the program of this stick for having garbage in the variable (there is laziness!).

  • @Lucashenrique I didn’t find any link in that forum, no reference to the word STL or any information indicating that you are stating. The subject there is completely different from what is being dealt with here. There speaks of manipulation of string And the algorithm is extremely complex, and this is about data entry. It may not seem like it, but the context in which it’s being used is very important to determine what to use. I think there’s a lot of "mayonnaise trip" in this conversation.

  • http://postimg.org/image/fq3ernjqx/ from my computer. Let’s explain what I mean in a final and succinct way (come on!). What is captured is stored in a buffer and has its size changed dynamically to each key (I suppose). The Std::string shows the way size is changed, and my code analogizes to it.

Show 4 more comments

Browser other questions tagged

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