Thread: fgets only returns 3 characters

  1. #31
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    Technically a null pointer does not have to be 0x00000000. It only has to be equal to an integer literal null, not necessarily any 0 integer cast to a pointer. So principally a compiler could be made to use another value as null, and allow 0x00000000 to be a valid pointer. However since on most systems comparing to 0 is a more trivial operation than comparing to some other arbitrary integer, this is not done.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  2. #32
    Registered User
    Join Date
    Aug 2008
    Posts
    129
    Quote Originally Posted by cas View Post
    This is unrelated to your question, but still important. Using header guards like this is great, but you should not define a name that starts with an underscore. The name _LIST_H is reserved for use by your compiler/library.
    Ehm, actually that's NetBeans' doing; I don't know anything about the compiler directives (although I think I have a good guess at some things). I've corrected it in my headers.

    I've been toying with my code a while to solve a segfault, but I can't get anywhere with it. GDB (GNU Debugger) shows the program as crashing when I declare char mode. Because I now have 4 files, I'm uploading them rather than posting them.
    Last edited by Jesdisciple; 08-23-2008 at 12:27 PM. Reason: deleted files

  3. #33
    Registered User
    Join Date
    Jan 2008
    Posts
    290
    The second parameter to fopen() is supposed to be a C string. C strings must be NUL terminated.

    Open the file like this:

    FILE *file = fopen(argv[1], "r");

    Also, your concat() function will not work properly. The first dimension in any array that you pass to a function will decay into a pointer to the element type of that array -- so, sizeof(array) will return the same as sizeof(char**), which is definitely not the total number of bytes used by your array.

    The proper way to handle that array, since you NULL terminated it, would be:
    Code:
    void concat(char *array[], void (*callback)(char *result)) {
       int i;
    
       // Check to make sure you weren't passed a NULL pointer
       if (!array || !array[0]) return;
    
       // Loop until you reach the NULL terminator
       for (i = 0; array[i] != NULL; i++)
          sum += strlen(array[i]);
    
       // etc...
    }
    However, I think you should reconsider even using the concat() function period. It would make much more sense to use sprintf() or fprintf() for what you are trying to accomplish:
    Code:
    if (!file) {
       fprintf(stderr, "Error: The file \"%s\" could not be opened; check its permissions and try again.", argv[1]);
       return 1;
    }
    Or even better:
    Code:
    #define eprintf(fmt, ...) fprintf(stderr, "%s() : line %d : " fmt, __func__, __LINE__, ##__VA_ARGS__)
    ...
    if (!file) {
       eprintf("Error opening file \"%s\"; check its permissions and try again.", argv[1]);
       return 1;
    }
    Which will give more helpful error messages with little effort:
    Code:
    >a.exe
    main() : line 9 : Error: At least one argument (a filename) must be provided.
    >a.exe blah
    main() : line 16 : Error opening file "blah"; check its permissions and try again.

  4. #34
    Registered User
    Join Date
    Aug 2008
    Posts
    129
    Code:
    "%s() : line %d : " fmt
    Is that string concatenation? I thought C couldn't do that.
    Code:
    ##__VA_ARGS__
    Do the hashes suppress errors?

    Does eprintf show the line where it was called, or does it track down the original caller? I.e., if I call it in readLine and call readLine from main, is the line number from readLine or main? (Either way, I don't understand the line numbers given above...)

    I'm now getting a segfault between the calls to readLine and link. I've updated the files below and deleted those above.
    Last edited by Jesdisciple; 08-26-2008 at 09:08 PM.

  5. #35
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    C concatenates two consecutive string literals. Often used when you have something that takes more than one line, or when half of the string literal comes from some pre-processor thing.

    I think ##__VA_ARGS__ is going to pass the ... from the "function" "call" into the var-args part of fprintf. (Never used it so not sure.)

    __LINE__ is standard C for "the line number you are currently on in the source code". You should be seeing the line number for the line eprintf is on.

    Were you getting a segfault before? I've lost track of what link is, and I don't know what the state of play was before this preprocessor bit.

  6. #36
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    Quote Originally Posted by Jesdisciple View Post
    Code:
    "%s() : line %d : " fmt
    Is that string concatenation? I thought C couldn't do that.
    It only works with string literals. fmt must be a string literal for this to work.
    When the macro is applied the result is:
    Code:
    fprintf(stderr, "%s() : line %d : " "Error opening file \"%s\",...
    So the two literal strings in a row get merged into one. Such syntax can also be used to split long strings into multiple lines of code.

    Does eprintf show the line where it was called, or does it track down the original caller? I.e., if I call it in readLine and call readLine from main, is the line number from readLine or main? (Either way, I don't understand the line numbers given above...)
    eprintf is expanded in the function that is is called. Then the preprocessor is applied again to the same line. This resolves __func__ and line __LINE__ within that context. Thus the preprocessor is applied repeatedly, until all macros are resolved, on each repetition ignoring previously resolved macros (so as to disallow recursion).
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  7. #37
    Registered User
    Join Date
    Jul 2008
    Posts
    133
    http://gcc.gnu.org/onlinedocs/gcc/Va...ariadic-Macros
    (## removes comma if va_args is empty)

  8. #38
    Registered User
    Join Date
    Jan 2008
    Posts
    290
    Code:
    struct object *line;
    line->length = 32;  // BAD
    line->pointer = calloc(line->length + 1, sizeof(char));
    
    struct charr *type;
    type->pointer = "string";  // BAD
    type->length = strlen(type->pointer);
    line->type = type;
    You never allocated any memory for a (struct object) or a (struct charr), yet you are trying to assign things to their fields. Declaring a pointer doesn't allocate any memory for what the pointer points at. Try declaring AND initializing those pointers:
    Code:
    struct object *line = malloc(sizeof(struct object));
    ...
    struct charr *type = malloc(sizeof(struct charr));
    You are doing this throughout your code. And what really puzzles me, is that you even remembered to free() a node after you're done with it.... but you never malloc'd it!

    Quote Originally Posted by Jesdisciple View Post
    Does eprintf show the line where it was called, or does it track down the original caller? I.e., if I call it in readLine and call readLine from main, is the line number from readLine or main? (Either way, I don't understand the line numbers given above...)
    The line numbers are absolute (relative to the beginning of the source file the macro was called in). If you call the macro in readLine(), then it will print "readLine()" followed by the line number in the source file that the macro call appeared on. You don't understand the line numbers in my example because I had made several modifications to your code, and thus the line numbers in my code wouldn't match yours.

    Quote Originally Posted by King Mir View Post
    Then the preprocessor is applied again to the same line. This resolves __func__ and line __LINE__ within that context.
    __func__ is actually a predefined identifier, not a preprocessing macro, so don't expect it to be expanded like __LINE__. More specifically, the compiler should behave as if this code were inserted immediately after the opening curly brace for the body of the function definition:
    Code:
    static const char __func__ [] = "function name";
    Last edited by arpsmack; 08-23-2008 at 01:19 PM.

  9. #39
    Registered User
    Join Date
    Aug 2008
    Posts
    129
    My program now executes normally. Thanks!

    Now I wonder if there's a function like printf that returns the formatted string rather than outputting it (or at least a toString for ints)?

  10. #40
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by Jesdisciple View Post
    My program now executes normally. Thanks!

    Now I wonder if there's a function like printf that returns the formatted string rather than outputting it (or at least a toString for ints)?
    Do you mean sprintf?

  11. #41
    Registered User
    Join Date
    Aug 2008
    Posts
    129
    That's it.

    I'm reading http://www.newty.de/fpt/callback.html#howto and http://www.linuxquestions.org/questi...n-in-c-285169/ and trying to implement the best practice, but GCC doesn't recognize the _USERENTRY calling convention. Why?

  12. #42
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by Jesdisciple View Post
    That's it.

    I'm reading http://www.newty.de/fpt/callback.html#howto and http://www.linuxquestions.org/questi...n-in-c-285169/ and trying to implement the best practice, but GCC doesn't recognize the _USERENTRY calling convention. Why?
    Because Microsoft and/or Borland made it up? The newty.de thing you linked to even explicitly states the difference between MS and GCC syntax in section 2.2. (If I remember correctly, and I probably don't, in C you're only going to have one type of calling convention anyway (I think stdcall is C++ only), and you're probably not writing in Pascal or anything funny like that, so hey. I've never used a cdecl declaration in a C-only program, but I've led a sheltered life.)

    Edit: And going through that same tutorial, you never see any mention of _USERENTRY except in that one example taken from Borland C++. I would not venture to say that explicitly mentioning the usual calling conventions in straight C is a best practice.
    Last edited by tabstop; 08-23-2008 at 10:39 PM.

  13. #43
    Registered User
    Join Date
    Aug 2008
    Posts
    129
    I'm surprised that wasn't mentioned in the LQ thread. :\

    Now I have another segfault, but (of course) I can't see why. I make two calls to charr:
    Code:
    charr(readLine(length, file));
    charr("charr");
    The first executes fine, but the second catches at the call to strlen:
    Code:
    struct charr{
        char *pointer;
        int length;
    };
    struct charr *charr(char *string){
        struct charr *this = malloc(sizeof(struct charr));
        this->pointer = string;
        this->length = strlen(string);
        return this;
    };
    What's different?

    EDIT: When I set a breakpoint in readLine it seemed to indicate that the bug is there, so here's that function... (The two calls are actually in the same statement with their values passed to another function; I guess they're being evaluated right-to-left.)
    Code:
    char *readLine(int length, FILE *stream){
        char *result = malloc(length * sizeof(char));
        fgets(result, length, stream);
        char *last = &result[length - 1];
        if(*last == '\n'){
            *last = '\0';
        }
        return;
    }
    Thanks for this whole thread!
    Last edited by Jesdisciple; 08-24-2008 at 01:47 PM.

  14. #44
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    I don't think this will fix your problem, but: length doesn't change as a result of fgets. So you should do something like
    Code:
    char *last = &result[strlen(result)-1];
    In fact as you have it, your test could never work, since fgets will put a \0 at the end of the string, so if it wrote the last character, result[length-1], it must have written a \0 there.

  15. #45
    Registered User
    Join Date
    Aug 2008
    Posts
    129
    Quote Originally Posted by tabstop View Post
    I don't think this will fix your problem, but: length doesn't change as a result of fgets. So you should do something like
    Code:
    char *last = &result[strlen(result)-1];
    In fact as you have it, your test could never work, since fgets will put a \0 at the end of the string, so if it wrote the last character, result[length-1], it must have written a \0 there.
    If it will put the \0 there anyway, why do I need to do the test at all? And I thought it would make the string exactly the length I supplied, not 1 more?

    EDIT: I found the bug! I forgot to return result;.
    Last edited by Jesdisciple; 08-24-2008 at 02:21 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Lame null append cause buffer to crash
    By cmoo in forum C Programming
    Replies: 8
    Last Post: 12-29-2008, 03:27 AM
  2. HELP!!!!emergency Problem~expert please help
    By unknowppl in forum C++ Programming
    Replies: 9
    Last Post: 08-21-2008, 06:41 PM
  3. HELP!!!!emergency ~expert please help
    By unknowppl in forum C Programming
    Replies: 1
    Last Post: 08-19-2008, 07:35 AM
  4. gets vs fgets
    By strobo in forum C Programming
    Replies: 10
    Last Post: 03-27-2002, 05:28 PM