Thread: scanf with realloc

  1. #1
    Registered User
    Join Date
    Apr 2009
    Location
    Turkey
    Posts
    12

    scanf with realloc

    I'm trying to get a string with unknown length and i used this weird code:

    Code:
    int main()
    {   char *ptr
        int l;
    
        ptr = (char *) malloc(sizeof(char *) * 10);
       
        while(scanf("%s", ptr) == 1)
             {
               l = strlen(ptr);
               if(l>10)
                  ptr = (char *) realloc(ptr,sizeof(char *) * (l-10));
             }
         ....
         return 0;
    }
    It seems not working . Any suggestions for how to get it worked?

  2. #2
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    %s stops at whitespace. Other than that, what do you mean by "not working"?

    Quzah.
    Hope is the first step on the road to disappointment.

  3. #3
    Registered User
    Join Date
    Apr 2009
    Location
    Turkey
    Posts
    12
    Quote Originally Posted by quzah View Post
    %s stops at whitespace. Other than that, what do you mean by "not working"?

    Quzah.
    Although I cared about that,still does not halt. Looks like infinite loop..

  4. #4
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    That's because it is an infinite loop if you keep providing it input. Oh, and you keep allocating a number of character pointers (or something), not actual space for the strings. So I don't know what you're really trying for there...

    Quzah.
    Last edited by quzah; 04-28-2009 at 08:59 PM.
    Hope is the first step on the road to disappointment.

  5. #5
    Registered User
    Join Date
    Apr 2009
    Location
    Russia
    Posts
    116
    zhankal,

    Code:
        ptr = (char *) malloc(sizeof(char *) * 10);
    to

    Code:
        ptr = (char *) malloc(sizeof(char) * 10);
    and for realloc too

    the loop is infinite because the standard input is continuing (push ctrl+d in lin or ctrl+z in win to end input)

  6. #6
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    That method will absolutely and surely not work. The reason being that scanf will read ALL avaialble data into the provided string. If that happens to be more than 10 bytes, then it will simply crash.

    If you want to read an arbitrary length string, you are most likely better off using either a loop doing fgets into a temporary buffer (say 10 or 100 bytes), and then concatenating the resulting string together into one that you use realloc to allocate, using strcat. Or use getchar(), and grow the space using realloc whenever you run out of space.

    scanf and gets are both functions that do not care one bit about whether the data fits or not!

    Finally, for almost any type of "arbitrary lenght input", I prefer to have a large, fixed size buffer, and then, if need be, allocate the space to store it permanently AFTER it's been read completely.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  7. #7
    Registered User
    Join Date
    Apr 2009
    Location
    Russia
    Posts
    116
    oh, really...

    zhankal, this an example only (I would write it in many functions for read the line (or word), all checks and so)

    it prints last line, and stores it in the correct size dynamic space

  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by c.user
    zhankal, this an example only (I would write it in many functions for read the line (or word), all checks and so)

    it prints last line, and stores it in the correct size dynamic space
    A few things to note:
    • You only need one dynamically allocated array since the temporary buffer can be fixed at 1000 char.
    • You only need to allocate for linep within the loop, initialising it to a null pointer before the loop so that realloc() works like malloc() on the first iteration.
    • With the correct use of strcat() or strncat() instead of strcpy(), along with sufficient expansion, you could do more than just print the last line, as matsp has noted.
    • There is no need to cast the return value of malloc() and realloc() to char* since the conversion from void* to char* is implicit.
    • sizeof(char) is always equal to 1.
    • There is no need to cast to void* before using free() since the conversion from char* to void* is implicit.
    • Default int should be avoided, hence main() should be declared as: int main() or int main(void).
    Last edited by laserlight; 05-01-2009 at 12:35 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #9
    Registered User
    Join Date
    Apr 2009
    Location
    Russia
    Posts
    116
    Quote Originally Posted by laserlight
    You only need one dynamically allocated array
    if he wants two, I do two

    Quote Originally Posted by laserlight
    You only need to allocate for linep within the loop
    if there will not a line >10 it will allocated only one time (what specially do you suggest I don't understand, allocate it in every loop ? or allocate it in the if (and what will be if all lines will be less then 10 ?))

    Quote Originally Posted by laserlight
    With the correct use of strcat() or strncat() instead of strcpy()
    I think topic starter wants save string to optimal array only

    Quote Originally Posted by laserlight
    There is no need to cast the return value of malloc()
    Oh, in C++ it needs
    I got a question why compiler print warnings when I write code without type cast, and I needed to edit it (I have a habit hence )

    Quote Originally Posted by laserlight
    sizeof(char) is always equal to 1
    I think you right, but I don't know why (I have no proofs, I know only char is smallest type and it has simplest alignment and it must have size which makes available to store a character of system in an object of this type)
    nowhere I saw "the char equivalent to one byte"

    Quote Originally Posted by laserlight
    Default int should be avoided, hence main() should be declared as: int main() or int main(void).
    only if you want to compile it with conforming to C99 or C++, because this rule started only these standards hence
    int main() - is old style (old C style definition)
    Last edited by c.user; 05-01-2009 at 01:17 AM.

  10. #10
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by c.user
    if there will not a line >10 it will allocated only one time (what specially do you suggest I don't understand, allocate it in every loop ? or allocate it in the if (and what will be if all lines will be less then 10 ?))
    What's the point of your "less than 10" optimisation? You already have a buffer of adequate size. In other words, your example does extra work for no good reason. Instead of reading line by line and discarding, it should be reading line by line and appending to the final output string. If you only want to read line by line up to a maximum of 999 characters and discard all except the last line, then dynamic memory allocation is pointless. A 1000 character fixed size buffer is all that is needed.

    Quote Originally Posted by c.user
    I think topic starter wants save string to optimal array only
    Maybe, but I think that it is more likely that zhankal just wants to know how to read a string of unknown length. My suggested modification of your code does have optimal space usage, but a more efficient method would be to expand the dynamic array by a factor rather than by the length of the newly read in string (and optionally resize after the loop if space consumption was a concern).

    Quote Originally Posted by c.user
    Oh, in C++ it needs
    I thought that you were the one preaching about not "mixing standards"
    The problem with this cast is that it can hide errors due to a failure to include <stdlib.h>. These errors would not apply to C++ where functions must be declared before use, but can apply to C where functions do not need to be declared before use under some circumstances.

    Quote Originally Posted by c.user
    I got a question why compiler print warnings when I write code without type cast, and I needed to edit it
    Which compiler is that? Or perhaps you forgot to #include <stdlib.h>?

    Quote Originally Posted by c.user
    I think you right, but I don't know why (I have no proofs, I know only char is smallest type and it has simplest alignment and it must have size which makes available to store a character of system in an object of this type)
    nowhere I saw "the char equivalent to one byte"
    Refer to section 3.3.3.4 of C90 or section 6.5.3.4 of C99:
    "When applied to an operand that has type char, unsigned char, or signed char, (or a qualified version thereof) the result is 1."

    Quote Originally Posted by c.user
    only if you want to compile it with conforming to C99 or C++, because this rule started only these standards
    So, what is so good about default int? Why is it better to write:
    Code:
    increment(int x)
    {
        return x + 1;
    }
    when you can be explicit and write:
    Code:
    int increment(int x)
    {
        return x + 1;
    }
    so that it is obvious that it is not a case where the author merely forgot about the return type?
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  11. #11
    Registered User
    Join Date
    Apr 2009
    Location
    Russia
    Posts
    116
    Quote Originally Posted by laserlight
    Which compiler is that? Or perhaps you forgot to #include <stdlib.h>?
    Oh, it was with malloc, i have remember it now
    with free it's ok, I tested with -Wall

    Quote Originally Posted by laserlight
    Refer to section 3.3.3.4 of C90 or section 6.5.3.4 of C99:
    ok, I have found

    Quote Originally Posted by laserlight
    when you can be explicit and write:
    I everytime write this type for all functions unless main, and so I know where is I don't have new standards (I can give it for any human, and he will not say to me "it is not compiling, because I have old compiler" (it will compile in any C compiler)), and if I use int main(), I know it is with C99
    I have many sources and I don't want to create folders for them, when I open the source, I see all about it
    you know C99 have a headers which C89 hasn't, I don't want to edit the code

    about topic, I allocate memory only once, and you suggest allocate memory every time (if I have a buffer which can take all line, why it must reallocate the space)
    I can write code without strcpy for only one buffer and reallocate it after the loop, but author doesn't do so (maybe he don't need it)

  12. #12
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by c.user
    I everytime write this type for all functions unless main (...) and if I use int main(), I know it is with C99 (...) you know C99 have a headers which C89 hasn't
    So you are using default int return type only for the main function as a way of documenting whether you are using C89 or C99? Methinks that it may be better to just use the presence of "//" style comments. In any case, how you want to document your programs is up to you; my request is that when you post code to these forums, practice good practices.

    Quote Originally Posted by c.user
    (I can give it for any human, and he will not say to me "it is not compiling, because I have old compiler" (it will compile in any C compiler))
    That is not relevant, since as I have pointed out, these programs will be compiled by any C89 and C99 conformant compilers:
    Code:
    int main(void)
    {
        return 0;
    }
    Code:
    int main(int argc, char* argv[])
    {
        return 0;
    }
    Quote Originally Posted by c.user
    about topic, I allocate memory only once, and you suggest allocate memory every time (if I have a buffer which can take all line, why it must reallocate the space)
    That is not accurate: you allocate memory on each iteration where the input exceeds 10 characters. Let me demonstrate a better version of your program:
    Code:
    #include <stdio.h>
    
    /* scan lines, save line to buffer and print last */
    int main(void)
    {
        char line[1000];
        while (scanf("%999[^\n]%*c", line) == 1)
            /* Do nothing in loop body */;
        printf("%s\n", line);
        return 0;
    }
    Basically, we are suggesting different things. I am suggesting that the program actually make good use of dynamic memory allocation, e.g., to append to a dynamically allocated string so that eventually all input is saved. A naive way of doing this would indeed involve memory allocation on every iteration; a better way would only expand the array when necessary by increasing the amount of memory allocated by a factor.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #13
    Registered User
    Join Date
    Apr 2009
    Location
    Russia
    Posts
    116
    new version without functions (as I would like)
    after the loop it places with the best fit

    I add a free call in the end of the program (if it will be continued then)
    Last edited by c.user; 05-03-2009 at 10:17 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. scanf() consideres useless
    By Snafuist in forum C Programming
    Replies: 15
    Last Post: 02-18-2009, 08:35 AM
  2. using realloc
    By bobthebullet990 in forum C Programming
    Replies: 14
    Last Post: 12-06-2005, 05:00 PM
  3. Replies: 2
    Last Post: 02-20-2005, 01:48 PM
  4. scanf issue
    By fkheng in forum C Programming
    Replies: 6
    Last Post: 06-20-2003, 07:28 AM
  5. scanf - data is "put back" - screws up next scanf
    By voltson in forum C Programming
    Replies: 10
    Last Post: 10-14-2002, 04:34 AM