read here that fgets() is bad, although no explanation given... also i think the default getline() isnt in C , is it??

why is fgets() bad??

also, the page on getline says it takes in char** as the 1st input type... whats a '**'? why is it used?? i couldnt get an answer when i googled it... any help?? :(

Recommended Answers

All 10 Replies

fgets() is bad only if you don't understand how it works. I'd wager that the label of "unreliable" in the page you linked to has to do with how fgets() handles partial lines. If the line in the stream is longer than the buffer provided to fgets() can hold, no newline is stored at the end. This way the programmer can check for a newline and make another call to get the rest of the line (or the next partial line)

This is correct in the presence of extra long lines:

char buf[BUFSIZ];

while (fgets(buf, sizeof buf, stdin)) {
    fputs(buf, stdout);

    /* Did we read a partial line? */
    if (buf[strlen(buf) - 1] == '\n')
        break; /* No, all done */
}

also i think the default getline() isnt in C , is it??

getline() isn't a standard function, it's a library extension under GCC. Therefore, getline() is also bad because it's not guaranteed to be supported. ;)

whats a '**'? why is it used??

It's a pointer to a pointer. The reason that getline() here uses it is because the pointer you pass may be reset to point to memory allocated within getline(). It's really just the same reason why you'd pass a pointer to an int if you want to modify the value of the int in a function:

void foo(int *p)
{
    *p = 123;
}

int main(void)
{
    int x = 0;

    foo(&x);
    printf("%d\n", x); /* Prints 123 */

    return 0;
}

Only here instead of an int, you want to modify the value of a pointer. Thus you pass a pointer to it.

commented: this is going to help a looot of people..! +2

and make another call to get the rest of the line

i want to append the next partial line to the partial line that was just read, what do i do then?

char buf[BUFSIZ];
while (fgets(buf, sizeof buf, stdin)) {
    fputs(buf, stdout);
    /* Did we read a partial line? */
    if (buf[strlen(buf) - 1] == '\n')
        break; /* No, all done */
    else
        strcat(bigDaddy,buf);
}

will this work?? i think it should work as long as bigDaddy is big enough :D

is there another more preffered way to this?

getline() is a c++ function not useful in C programs. As for fgets() being unreliable, it isn't if you use it correctly.

If you know bigDaddy is big enough why not just use that as the parameter to fgets() instead of buf? In any event, the program needs to execute line 8 regardless of whether the '\n' exists or not because otherwise bigDaddy won't contain all the data.

It might be better to make bigDaddy a pointer so that memory can be allocated to it as needed. In the loop just reallocate bigDaddy to hold the curerent string plus the new string.

char* bigDaddy = NULL;
char buf[BUFSIZE];
char* ptr;
while( fgets(buf,sizeof(buf),fp) )
{
    bigDaddy = realloc(bigDaddy, strlen(bugDaddy)+strlen(buf)+1);
    strcat(bigDaddy, buf);
    if( (ptr = strrchr(bigDaddy,'\n')) != NULL)
    {
        *ptr = '\0';
        break;
    }
}

will this work?? i think it should work as long as bigDaddy is big enough :D

You have the basic idea, though don't forget to populate bigDaddy with the first partial line or the full line if buf is big enough:

char buf[BUFSIZ];

bigDaddy[0] = '\0'; /* Empty bigDaddy for strcat */

while (fgets(buf, sizeof buf, stdin)) {
    strcat(bigDaddy, buf); /* Always append the buffer */

    if (buf[strlen(buf) - 1] == '\n')
        break; /* Only break when a full line is read */
}

As AD mentioned, if bigDaddy is already big enough then just read directly into it. The partial line stuff with fgets() is mostly for when you're building a string dynamically and don't know how long the line might be (or similar situations).

getline() is a c++ function not useful in C programs.

A fact which is totally irrelevant to this thread because the getline() function being discussed is a C function provided by GCC. See the link in the first thread that says "read here"? It would be a good idea to read there before making assumptions. ;)

I did "read here", that's why I commented on getline(). If that's a C function in gcc then I'd suggest not usuing it either because it isn't portable, just as everything in conio.h isn't portable. Non-portable code has always been discouraged here.

The getline function is the preferred method for reading lines of text from a stream, including standard input.

the pointer you pass may be reset to point to memory allocated within getline()

im a bit unclear here...

1.memory allocated with getline() ??

  my_string = (char *) malloc (nbytes + 1);
  bytes_read = getline (&my_string, &nbytes, stdin);

malloc allocates memory to my_string[], according to user input (nbytes). hoe does getline allocate memory ?

also;

    free(my_string);
    my_string=NULL;

is this whats meant by pointer resetting?? i looked it up on the net, the code examples seemed huge.. lost patience :| they said something like "setting a pointer so that it points to 0" , so i assume this is what they mean?

As AD mentioned, if bigDaddy is already big enough then just read directly into it. The partial line stuff with fgets() is mostly for when you're building a string dynamically and don't know how long the line might be (or similar situations).

thankyou :) got it :)

edit:
this place says to store a backup copy of the pointer,

this place says this about realloc:

void * realloc ( void * ptr, size_t size );

size
New size for the memory block, in bytes.
If it is 0 and ptr points to an existing block of memory, the memory block pointed by ptr is deallocated and a NULL pointer is returned.

why do that to make a pointer null? if pointer is to be made null, free() + pointer=NULL seems good enough.. ?

hoe does getline allocate memory ?

Consider this example:

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

void foo(char **p, size_t bytes)
{
    *p = malloc(bytes);
}

int main(void)
{
    char *s;

    foo(&s, 15);
    strcpy(s, "this is a test");
    puts(s);
    free(s);

    return 0;
}

foo() is passed a pointer to a pointer, it then dereferences that pointer and allocates memory to the pointed to pointer. This is more or less the same functionally as if you allocated the memory to s directly in main(). That's what getline() does, except it does so in a way that guarantees (barring allocation errors) the string will be big enough to hold an entire line.

is this whats meant by pointer resetting??

It means to change where the pointer points to.

why do that to make a pointer null? if pointer is to be made null, free() + pointer=NULL seems good enough.. ?

I think you misunderstood that paragraph. realloc() doesn't set the pointer to NULL, it can't. That part of the documentation is describing realloc()'s unfortunate overloaded behavior. Here's what it means with examples:

realloc(NULL, 5) == malloc(5)
realloc(p, 0)    == free(p)

And because realloc() returns a pointer to void, in the "free" case it simply returns a null pointer. However, the documentation you linked to is outdated. Please bear with me for a moment because I'm going to get into minutia of the C standard.

The C89 standard explicitly states that realloc(p, 0) behaves the same way as free(p): "If size is zero and ptr is not a null pointer, the object it points to is freed".

Okay, so what's the problem? The problem is that C89 is no longer the current official standard, it's an older version of the standard that's been overridden by no less than two revisions. The C99 standard changes this behavior (and it's pulled forward in C11). It says exactly this for the definition of realloc():

The realloc function deallocates the old object pointed to by ptr and returns a pointer to a new object that has the size specified by size. The contents of the new object shall be the same as that of the old object prior to deallocation, up to the lesser of the new and old sizes. Any bytes in the new object beyond the size of the old object have indeterminate values.

If ptr is a null pointer, the realloc function behaves like the malloc function for the specified size. Otherwise, if ptr does not match a pointer earlier returned by the calloc, malloc, or realloc function, or if the space has been deallocated by a call to the free or realloc function, the behavior is undefined. If memory for the new object cannot be allocated, the old object is not deallocated and its value is unchanged.

Returns

The realloc function returns a pointer to the new object (which may have the same value as a pointer to the old object), or a null pointer if the new object could not be allocated.

You'll notice that nowhere does it mention anything along the lines of behaving like free(). Further, the behavior when size is 0 has been relegated to unspecified behavior here:

The amount of storage allocated by a successful call to the calloc, malloc, or realloc function when 0 bytes was requested (7.20.3).

And implementation defined behavior for the return value here:

Whether the calloc, malloc, and realloc functions return a null pointer or a pointer to an allocated object when the size requested is zero (7.20.3).

Technically, not even C89 explicitly said that realloc() returns NULL in the case of realloc(p, 0), but that's the only logical inference. There's also an ambiguity because C89 has this line in the implementation defined portability warnings:

The behavior of the calloc, malloc, or realloc function if the size requested is zero (4.10.3).

The explicit requirement of behaving like free(p) for realloc(p, 0) should take precedence over implementation choice, but it's still an ambiguity. This is more reason not to rely on the free()-like behavior of realloc() even for C89.

    char *s;
    foo(&s, 15);
    strcpy(s, "this is a test");

in these lines, s is transformed from a character to a character array that contains the string "this is a test" ... this is whats happening here right? and thus foo() allocates memory to s... im getting it...

This is more or less the same functionally as if you allocated the memory to s directly in main().

yup! got it.. i think...

as regards the c11 standard, can u givesome links? i follow that page (c89 one) completely, so i guess im missing a lot perhaps...

If ptr is a null pointer, the realloc function behaves like the malloc function for the specified size.

so a pointer declared as static will have the same effect when fed to a realloc() as in case of a malloc()...?
but what if the pointer was originally pointing to something else?? do we do a {free() + pointer=NULL} on it? is it a good way? or we reset it??

if reset; then is reset ==
1. keeping an original copy of the pointer,
2. assigning that original to the pointer at a later time

is this the default way to reset?

You'll notice that nowhere does it mention anything along the lines of behaving like free()

the idea i had was something like this:

free() makes a dangling pointer, that gives need to assign NULL to it... ? so the place it says

The realloc function returns . . . . . a null pointer if the new object could not be allocated.

thus, by definition, shouldn't realloc serve as an improved version of free() ?? as the dangling pointer issue is no longer there... is this idea justified?

in these lines, s is transformed from a character to a character array that contains the string "this is a test" ... this is whats happening here right?

s is a pointer to a character. Passing the address of s to foo() means that foo() can allocate memory to s. Then s is treated as if it were an array. Please don't confuse arrays and pointers, they're not the same thing.

so a pointer declared as static will have the same effect when fed to a realloc() as in case of a malloc()...?

What does static have to do with anything?

but what if the pointer was originally pointing to something else?? do we do a {free() + pointer=NULL} on it? is it a good way? or we reset it??

if reset; then is reset ==
1. keeping an original copy of the pointer,
2. assigning that original to the pointer at a later time

is this the default way to reset?

I don't understand the question.

free() makes a dangling pointer, that gives need to assign NULL to it... ?

You don't need to assign NULL to the pointer, just don't use it until you've pointed it back to something that you own.

thus, by definition, shouldn't realloc serve as an improved version of free() ??

No, because by definition, realloc() could allocate memory that itself needs to be freed if you pass a size of 0. Thus you're right back where you started of needing to call free(). The only time you don't need to call free() is when realloc() returns NULL, but it's not required to do so when the size is 0. That was my point to begin with.

i messed up there... perhaps posted on a hurry..

im going through everything again.. inlight of what u said.. hopefully wont mess up this time...

thank you so much for the detailed answers, learning alot.. :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.