2

I want to write a program which asks user some input values and gives results according to the input values. The following code works but when I enter "John" only 4 spaces are used in the 100 memory. Other 96 are wasted. Also, there is no guarantee that input will be smaller than 100 characters (very unlikely but possible). Is there a way to optimize this?

P.S: When I researched about it, some sites say I should use sscanf() or fgets() but I didn't understand how to use them in my code.

P.P.S : I am very new to C so please show me the simplest way.

#include <stdio.h>
int main()
{
     char name[100];
     printf("Your name: \n");
     scanf("%100s", name);
     printf("Name: %s  \n", name);

    return 0;
}
4
  • 1
    Take a look: How can I read an input string of unknown length? Commented Jun 29, 2017 at 16:43
  • I saw that discussion but I couldn't understand what the first answer said. It looked a little complicated. Commented Jun 29, 2017 at 16:46
  • In a nutshell, the answer linked above reads the user input one character at a time and uses dynamic memory allocation for the input buffer, allocating 16 bytes more at a time as needed as the number of characters input increases. If you take the time to study that answer line by line and look up the documentation and use of the functions involved, you'll learn a bit about C programming. Commented Jun 29, 2017 at 16:57
  • scanf("%100s", name);-- note that this should be scanf("%99s", name); to avoid buffer overflow. The \0 character is automatically written by scanf() when using %s; the maximum width specified is the maximum length of an input item, not including the null-terminator. Commented Jun 29, 2017 at 18:43

3 Answers 3

3

You need to realloc memory for this operation( the memory will be changed when the program is running )

char *name = 0;
char *tmp = 0;
int inputAsingleChar,i=0,j=4;
printf("Your name: \n");
while((inputAsingleChar = getchar()) != '\n' && inputAsingleChar != EOF)
{
    if(i==j){
        j+=4;
        tmp = realloc(name, j);
        if(tmp== NULL){printf("Couldn't realloc but the 'name' array is still valid");}
        else{name = tmp;}
    }
    name[i++] = inputAsingleChar ;
}
name[i] = '\0';
printf("Name: %s  \n", name);
free(name);
free(tmp);

Version 2 (Final Version) with the help of the generous David Bowling

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

int main(void)
{
    int inputAsingleChar,i=0,j=4;
    char *name = malloc(j);
    if (name == NULL){
        printf("No memory");
        exit(1);
    }
    printf("Your name: \n");
    while((inputAsingleChar = getchar()) != '\n' && inputAsingleChar != EOF)
    {
        if(i==j){
            j+=4;
            char * tmp = realloc(name, j);
            if(tmp== NULL){printf("Couldn't realloc but the 'name' array is still valid");}
            else{name = tmp;}
        }
        name[i++] = inputAsingleChar ;
    }
    name[i] = '\0';
    printf("Name: %s  \n", name);
    free(name);
    return 0;
}

Also is live here http://ideone.com/cDxkDV

Sign up to request clarification or add additional context in comments.

17 Comments

It is very ineffcitient but yeah, it works. Btw, what is c here?
@tilz0R At least it didn't wastes resources in future . If Harold wants to make that input an username he can simply use an array with 16 bytes.But he wants to no waste bytes
Not much sense in worrying about 95 bytes for one name. This might matter when storing many names; then it is better to use a generous buffer and copy to custom-allocated memory, or to trim allocations to size with realloc(). IAC, this answer is very inefficient with so many unnecessary allocations. Why malloc 4 characters at the start, when you just realloc() to 2 in the first loop iteration? Also, there is a potential memory leak with: name = realloc(name, i+1);. There is no reason for this bad practice to be used in an accepted answer.
Hmmm. Now there is UB since name[i++] = inputAsingleChar; occurs before the call to realloc(). Efficiency aside, (best when growing memory to grow from reasonable size to needed size by periodic doubling), my main complaint is with assigning the result of realloc() directly to the pointer to the object of reallocation. realloc() may return a null pointer, then losing access to the previous allocation, causing a memory leak and lost data. Simple to illustrate good practice for learners by first storing in and then checking a temporary variable.
There are some issues. 1) tmp is not declared. 2)tmp should not be realloced twice, but reassigned, and not freed, as this deallocates the recent reallocation. 3) need to do some allocation before assigning name[i++] = .... 4) sizeof(name) gives the size of a pointer, not an array. There are some typos too; suggest compiling with #includes and main() to test before posting. Here is an Ideone link to an improved version of your code. I have used doubling here, but you could just as well grow with j += 4;.
|
1

No, there is no way. You have to make sure you have enough memory to save data from user at any time. Maybe at some point user will try to write 100 characters. In this case, you need 101 bytes available in memory for trailling zero.

If you use sscanf or gets you still need memory to save your string and in both cases you don't know how many bytes you can expect from input.

The following code works but when I enter "John" only 4 spaces are used in the 100 memory. Other 96 are wasted.

No, other 95 are wasted, you are missing trailling zero.


If you want to do inefficient code, then you can realloc memory for each received character but then you have to read char by char from input using getchar function.


Further reading

How can I read an input string of unknown length?

Comments

1

If you are concerned about memory usage, use dynamic allocation of memory i.e using malloc() and realloc(), you can get certain behavior, like this.

int main() {

 char a;
int i=0;
char *str=0;
while((a=getchar())!='\n')
{
    str=realloc(str,i+2);   //1 for character to store, + 1 for '\0' terminating character
    str[i++]=a;      
}
 str[i]='\0';
printf("%s\n",str);
return 0;

} As the user enters the character, this code generates the memory and stores the results immediately. As user press Enter, the input reading process terminates.

This method is quite memory efficient, but takes more time to execute. So, always we need to manage the trade-off between performance vs memory. Hope this helps.

3 Comments

Thanks, it looks like it will help me to save some space.
if you have any other doubts, you can ask.
@anil Did you mean strlen(str) instead of sizeof(str)? Doing sizeof on a pointer always returns the same value.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.