Thread: A custom gets function

  1. #1
    Registered User
    Join Date
    Feb 2008
    Posts
    9

    A custom gets function

    Hello there,
    I am trying to implement a custom gets function which would allow me to read a string so as to avaoid the pitfalls associated with the C version of 'gets'.

    Well...I have been able to get some breakthrough into it. What my function does it that it keeps on extending the buffer (to hold the string) size by 16 if the user enters a string longer than 16 until it encounters the '\n' character. Im doing a char by char read using getchar and i check for the '\n' character and for the number of chars entered as of yet.

    So if the user string is more than 4(size of the original buffer) but less than 16, it works fine though it only displays the first 4 chars..but if the user string is >16 then issues do arise.

    Im wondering why...the seg fault occurs at the line preceded by an arrow-head in the program below

    Code:
    #include <stdio.h>
    #include "mygets1.h"
    
    int main()
    {
        char  b1[] = "ABCD";
        char  b2[] = "LMNO";
        char  b3[] = "ZYXW";
        
        puts(b1);
        puts(b2);
        puts(b3);
        putchar('\n');
        
        puts("Enter some characters:");
        mygets(b2);
    
        putchar('\n');
        puts(b1);
        puts(b2);
        puts(b3);
        
        return(0);
    }
    
    //mygets1.h - - -  my gets function 
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    char* mygets(char str[]); //func prototype
    
    char* mygets(char str[])
    
    {
        //    char *str;
        unsigned int i = 0;
        int bffr_fl = 1; //flag to check the if user input exceeds 4 chars
        int mul_factor = 1; //how many 16-char wide chunks do we need?
        int tmp; //holder for the multiplication (see below)
        size_t sze = strlen(str);
    
        while ((str[i] = getchar()) != '\n'){
            i++;
            if(i >= sze && bffr_fl) {
                    str = realloc(str,16*sizeof(char));//increase the size to 16
                    bffr_fl = 0;
                    mul_factor++;
            }
            else if(i % 16 == 0) {
               tmp = 16*mul_factor;         
    -->       str = realloc(str,tmp*sizeof(char));//add another 16-wide chunk  to the tail
                mul_factor++;
            }
        }
        printf("the user pressed enter at position number %d\n",i);
        str[i] = '\0'; //append a trailing null after the last char
        return str;
    }
    Id be pleaed if you could come up with some suggestions. Like what I plan now is to use something else for the first extension of the string and then start using realloc iteratively.

  2. #2
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Just so you know, fgets is a safe alternative to gets.
    The problem with your function is that you're taking a pointer to a buffer on the stack. The size of such buffers cannot be changed.
    Realloc can only reallocate buffers allocated on the heap with malloc or calloc.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  3. #3
    Jack of many languages Dino's Avatar
    Join Date
    Nov 2007
    Location
    Chappell Hill, Texas
    Posts
    2,332
    Same as the other thread. You're passing a CONST CHAR * pointer to mygets().

    Todd
    Last edited by Dino; 02-01-2008 at 01:44 PM. Reason: Elysia said it more succinctly

  4. #4
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    The pointer you give to realloc must have come from malloc (or calloc, or realloc), since realloc must free the original memory. You must have initialized your string before calling realloc.

  5. #5
    Registered User
    Join Date
    Feb 2008
    Posts
    9
    hmmm..
    yea it sure is...but then one has to know the size before hand...

    but Im trying to experiment with the idea of 'dynamic strings in C' ....I could instead use a bufffer big enough or I could dynamically create one such big buffer then free it...

    Perhaps what I wanna know is why the second time I use realloc it gives me an error...I have read from here that realloc can only work on pointers to memory which have been previously allocated using malloc/calloc/realloc...

    The pointer you give to realloc must have come from malloc (or calloc, or realloc), since realloc must free the original memory. You must have initialized your string before calling realloc.
    well...I did use realloc to increase the size of the mem chunk...do you mean that I should have created a new pointer variable and then have itpointed to at the newly allocated memory?..

    Hope to get some info...

    BR,
    Aijaz
    Last edited by aijazbaig1; 02-01-2008 at 01:49 PM. Reason: response

  6. #6
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by aijazbaig1 View Post
    Perhaps what I wanna know is why the second time I use realloc it gives me an error...I have read from here that realloc can only work on pointers to memory which have been previously allocated using malloc/calloc/realloc...
    so..it should be fine as I had used realloc before and then used it again in the second part of the for loop...
    Undefined behavior.
    What you need to do is
    a) take a pointer-to-pointer to hold the buffer
    b) return a buffer
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #7
    Registered User
    Join Date
    Feb 2008
    Posts
    9
    What you need to do is
    a) take a pointer-to-pointer to hold the buffer
    b) return a buffer
    You mean the first time I used the realloc function it allocated for me a part of the memory from the stack and not the heap (as function calls are locally allowed to use resources from the stack right?)

    So the pointer that must be passed to this function should instead be a pointer to a pointer (or a handle as they say) and I should make that handle point to the location of this buffer (thus it would be holding another address).

    But what about the memory allocation part of the function? would such a memory be rendered useless once we exit the function?

  8. #8
    Jack of many languages Dino's Avatar
    Join Date
    Nov 2007
    Location
    Chappell Hill, Texas
    Posts
    2,332
    Quote Originally Posted by Elysia View Post
    What you need to do is...
    ...upgrade to C++

  9. #9
    Registered User
    Join Date
    Feb 2008
    Posts
    9
    well..

    I may have to use C latter in school or my thesis work to handle low level stuff and Ive heard that C is better than C++ on such low level stuff...

    Perhaps isn't such problems intersting to explore?..

  10. #10
    Jack of many languages Dino's Avatar
    Join Date
    Nov 2007
    Location
    Chappell Hill, Texas
    Posts
    2,332
    Yes they are interesting to explore.

  11. #11
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by aijazbaig1 View Post
    but Im trying to experiment with the idea of 'dynamic strings in C' ....I could instead use a bufffer big enough or I could dynamically create one such big buffer then free it...
    So you're basically trying to create a C version of the C++ string class?
    In that case, maybe you could create a struct string that contains the char* pointer and the size of the buffer, and maybe the length of the string (so you don't have to keep calling strlen() on the string)...

  12. #12
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Right, if we were to implement the simplest (but not the most efficient) form of realloc, it would look something like this:
    Code:
    void *myrealloc(void *oldptr, size_t newsize)
    {
        size_t oldsize = magicalFindSize(oldblock);   /* See comment below */
        void *newptr;
        if (newsize != oldsize)
        {
            newptr = malloc(newsize);
            if (newptr != NULL)
            {
                memcpy(newptr, oldptr, MIN(oldsize, newsize));
                free(oldptr);
            }
            return newptr;
        } 
        /* No size change, so no need to change the allocation */
        return oldptr;
    }
    The function "magicalFindSize" will dig out the "admin" block for this allocation, and find out what size the block is. It's not really important.

    What is important is the bit in red: The freeing of the original pointer. If that pointer wasn't originally from a malloc/realloc call, then things are going to go horribly wrong at some point sooner or later [quite possibly LATER].

    A real realloc will have some more logic in it, where it looks to see if there is more space right behind the current allocation that we can use directly, rather than doing a complete new allocation, and such things - but that doesn't change the matter that sooner or later the original allocation will most likely be freed.

    --
    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.

  13. #13
    Registered User
    Join Date
    Feb 2008
    Posts
    9
    thnks for the reply,
    Code:
    newptr = malloc(newsize);
            if (newptr != NULL)
            {
                memcpy(newptr, oldptr, MIN(oldsize, newsize));
                free(oldptr);
            }
            return newptr;
    well..this does seem to be a simple and good implementation of the re-alloc. What I would wanna know is that elysia said that all memory allocated within a function call is allocated on the stack. And then what happens to the content of that memory location once we exit the function?

    Well...does that mean that I would not be able to use str to point to some memory allocated within this function and then extend the size of the block again using realloc?
    Last edited by aijazbaig1; 02-01-2008 at 02:55 PM.

  14. #14
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by aijazbaig1 View Post
    What I would wanna know is that elysia said that all memory allocated within a function call is allocated on the stack. And then what happens to the content of that memory location once we exit the function?
    That data disappears with the function, unless you allocate it on the heap. Data on the heap must be explicitly freed, so it will stay after the function.

    First and foremost - you are not looking for a handle. No, sir. A handle is not a pointer to pointer.
    In this case, you need char**. A pointer to char*. The reason you need this is because the data must be on the heap in order to resize it using realloc. And data on the heap needs a pointer. So therefore, main must have a pointer to the data and your mygets must take a pointer to that pointer.
    Easy enough, yes?
    Or you can just let the function itself allocate the memory and return a buffer.

    And secondly: no, C is not more efficient than C++ at low level stuff. That's a myth. Yes, C++ can be slower, but if you use it properly, like C, it is just as fast as C. I always dislike using C for the reason it's so limited and C++ can do everything C can (and equally good, as well) plus more.
    I do recommend you use C++ instead. If you can't use C++ classes and such, you can always fall back on using typical C code within C++. No, it won't compile straight away, but 99% of it will.
    Then you'll have the advantages of C++ and the speed of C at your disposal. Not a bad deal, eh?
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  15. #15
    Registered User
    Join Date
    Feb 2008
    Posts
    9
    First and foremost - you are not looking for a handle. No, sir. A handle is not a pointer to pointer.
    thnks for the info...seems that the term is a bit too vague and does not neccesarily mean a pointer to a pointer....go google!!

    In this case, you need char**. A pointer to char*. The reason you need this is because the data must be on the heap in order to resize it using realloc. And data on the heap needs a pointer. So therefore, main must have a pointer to the data and your mygets must take a pointer to that pointer.
    So you mean I should instead pass to this function a pointer to b2(the string b2 that is). And my mygets function should then allocate more space as and when needed?.. you also said
    Or you can just let the function itself allocate the memory and return a buffer.
    ..well...as before if I do that allocation within the function won't it get allocated on the stack again?...is there a way to specify that I'd like to have it allocated on the heap?...

    What exactly do you mean by a buffer..I hope its just a memory block pointed to by some pointer right?...

    BR,
    Aijaz

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Seg Fault in Compare Function
    By tytelizgal in forum C Programming
    Replies: 1
    Last Post: 10-25-2008, 03:06 PM
  2. Troubleshooting Input Function
    By SiliconHobo in forum C Programming
    Replies: 14
    Last Post: 12-05-2007, 07:18 AM
  3. Brand new to C need favor
    By dontknowc in forum C Programming
    Replies: 5
    Last Post: 09-21-2007, 10:08 AM
  4. Screwy Linker Error - VC2005
    By Tonto in forum C++ Programming
    Replies: 5
    Last Post: 06-19-2007, 02:39 PM
  5. c++ linking problem for x11
    By kron in forum Linux Programming
    Replies: 1
    Last Post: 11-19-2004, 10:18 AM