Using fgets, removing last character

This is a discussion on Using fgets, removing last character within the C Programming forums, part of the General Programming Boards category; Originally Posted by Thantos Most likely gets() was implamented before fgets(). Now the question is why the still allow it ...

  1. #16
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by Thantos
    Most likely gets() was implamented before fgets(). Now the question is why the still allow it to live
    So you can still compile and run old crappy code.

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

  2. #17
    & the hat of GPL slaying Thantos's Avatar
    Join Date
    Sep 2001
    Posts
    5,681
    It should be a compile time error with a message like:
    What the hell are you thinking using gets(). Don't you know that the devil himself will raise up by using this function? Begone heathen!
    Or something like that

  3. #18
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by Thantos
    It should be a compile time error with a message like: Or something like that
    It should just delete the file you're compiling.

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

  4. #19
    C Programmer Stack Overflow's Avatar
    Join Date
    Apr 2004
    Posts
    477
    Wow,

    This function must be hated world-wide I'll be sure to never use it, even if bribed with the most amount of money immaginable. fgets() forever!

    - Stack Overflow
    Segmentation Fault: I am an error in which a running program attempts to access memory not allocated to it and core dumps with a segmentation violation error. This is often caused by improper usage of pointers, attempts to access a non-existent or read-only physical memory address, re-use of memory if freed within the same scope, de-referencing a null pointer, or (in C) inadvertently using a non-pointer variable as a pointer.

  5. #20
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,006
    Quote Originally Posted by Stack Overflow
    I like the method:
    Code:
    if( (c=strrchr( buf, '\n' )) )
        *c='\0';
    It's the fastest, safest, and most reasonable approach in my view to remove the '\n' character from the string.
    I am not disagreeing with strrchr being safe and reasonable, but I do have a few comments on it being the fastest.

    The call to strrchr may need to start at the beginning of the string, look for the null terminator, and then begin the backwards search for the newline. If it's there, you'll find it right away. If it isn't there, you'll have to go all the way back to the beginning of the string before it returns NULL.

    Using strchr might be slow as well, because it looks for the newline and it looks for the terminating null for each character from beginning to the end.

    When immedaitely following a call to fgets, the newline (if it is there) will be at the end right before the terminating null. Now since we know that the newline will only be at the end, why not just look there? Call strlen, back up one, and look for a newline. If it is there, replace it with a null.

    This is a comparison thingy I'd written a while ago.
    Code:
    #include <stdio.h>
    #include <string.h>
    #include <time.h>
    
    char *foo(char *s)
    {
       size_t len = strlen(s);
       char *newline = s + len - 1;
       if ( *newline == '\n' )
       {
          *newline = '\0';
       }
       return s;
    }
    
    char *bar(char *s)
    {
       char *newline = strrchr(s, '\n');
       if ( newline )
       {
          *newline = '\0';
       }
       return s;
    }
    
    char *baz(char *s)
    {
       char *newline = strchr(s, '\n');
       if ( newline )
       {
          *newline = '\0';
       }
       return s;
    }
    
    char *qux(char *s)
    {
       strtok(s, "\n");
       return s;
    }
    
    char *zed(char *s)
    {
       size_t newline = strlen(s) - 1;
       if ( s [ newline ] == '\n' )
       {
          s [ newline ] = '\0';
       }
       return s;
    }
    
    #define BIND(j)   {j,#j}
    
    int main(void)
    {
       static const struct
       {
          char *(*call)(char*);
          const char *name;
       } function[] =
       {
          BIND(foo), BIND(bar), BIND(baz), BIND(qux), BIND(zed)
       };
       char text[][45] =
       {/* 01234567890123456789012345678901234567890123 */
          "All work and no play makes Jack a dull boy!\n",
          "The quick brown fox jumps over the lazy dog.",
       };
       size_t i,j,k;
       for ( i = 0; i < sizeof text / sizeof *text; ++i )
       {
          for ( j = 0; j < sizeof function / sizeof *function; ++j )
          {
             clock_t end, start;
             start = clock();
             for ( k = 0; k < 50000000; ++k )
             {
                text[0][43] = '\n';
                function[j].call(text[i]);
             }
             end = clock();
             printf("%s: %g, \"%s\"\n", function[j].name,
                    (end - start) / (double)CLOCKS_PER_SEC,
                    function[j].call(text[i]));
             fflush(stdout);
          }
          putchar('\n');
       }
       return 0;
    }
    
    /* my output
    foo: 3.055, "All work and no play makes Jack a dull boy!"
    bar: 3.835, "All work and no play makes Jack a dull boy!"
    baz: 8.102, "All work and no play makes Jack a dull boy!"
    qux: 16.884, "All work and no play makes Jack a dull boy!"
    zed: 3.075, "All work and no play makes Jack a dull boy!"
    
    foo: 3.174, "The quick brown fox jumps over the lazy dog."
    bar: 9.654, "The quick brown fox jumps over the lazy dog."
    baz: 8.202, "The quick brown fox jumps over the lazy dog."
    qux: 17.014, "The quick brown fox jumps over the lazy dog."
    zed: 3.105, "The quick brown fox jumps over the lazy dog."
    */
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

  6. #21
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Naturally, your mileage may vary...
    foo: 13.16, "All work and no play makes Jack a dull boy!"
    bar: 10.46, "All work and no play makes Jack a dull boy!"
    baz: 10.84, "All work and no play makes Jack a dull boy!"
    qux: 27.84, "All work and no play makes Jack a dull boy!"
    zed: 12.87, "All work and no play makes Jack a dull boy!"

    foo: 12.88, "The quick brown fox jumps over the lazy dog."
    bar: 9.98, "The quick brown fox jumps over the lazy dog."
    baz: 10.69, "The quick brown fox jumps over the lazy dog."
    qux: 27.98, "The quick brown fox jumps over the lazy dog."
    zed: 12.49, "The quick brown fox jumps over the lazy dog."


    gcc (GCC) 3.2.3 (Debian)
    Copyright (C) 2002 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions. There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    In my case, both times, strrchr is the fastest implementation.

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

  7. #22
    End Of Line Hammer's Avatar
    Join Date
    Apr 2002
    Posts
    6,231
    >>strrchr is the fastest implementation
    You really care about speed when processing a single line of user input?!

    My "method of the moment" is to strtok() it. OK, it may be more of an overhead, but it saves typing, and shortens my source, and doesn't require validation (of course the fgets() call does though).
    >>strtok(input, "\n");
    When all else fails, read the instructions.
    If you're posting code, use code tags: [code] /* insert code here */ [/code]

  8. #23
    C Programmer Stack Overflow's Avatar
    Join Date
    Apr 2004
    Posts
    477
    Well,

    I do know for a fact:
    Code:
    if ((c = strrchr(sentence, '\n')))
        	*c = '\0';
    Sure is alot faster and safer than:
    Code:
    sentence[strlen(sentence) - 1] = '\0';
    Or, at least I know that much now.


    - Stack Overflow
    Segmentation Fault: I am an error in which a running program attempts to access memory not allocated to it and core dumps with a segmentation violation error. This is often caused by improper usage of pointers, attempts to access a non-existent or read-only physical memory address, re-use of memory if freed within the same scope, de-referencing a null pointer, or (in C) inadvertently using a non-pointer variable as a pointer.

  9. #24
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    char *foo(char *s)
    {
    size_t len = strlen(s);
    char *newline = s + len - 1;
    if ( *newline == '\n' )
    {
    *newline = '\0';
    }
    return s;
    }
    The problem with that though is if the string has a length of 0 you will be working with an invalid index (-1).
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  10. #25
    C Programmer Stack Overflow's Avatar
    Join Date
    Apr 2004
    Posts
    477
    Ah,

    Yes I see that now. I never got the chance to try it but yeah -1 is an invalid index I believe. How does this implementation look, does it contain any flaws or is it any faster than strrchr() itself?

    Code:
    char* jar(const char *, int);
    char* har(const char *, int);
    
    int main() {
    	char *c;
    	char sentence[25] = "Testing\n";
    	char sentence2[15] = "Testing\n";
    
    	if (c = jar(sentence, '\n'))
    		*c = '\0';
    
    	if (c = har(sentence2, '\n'))
    		*c = '\0';
    
    	return 0;
    }
    
    char* jar(const char *string, int c) {
    	char *s, cc = c;
    	char *sp = (char *)0;
    
    	s = (char *)string;
    
    	while (*s) {
    		if (*s == cc)
    			sp = s;
    		s++;
    	}
    	if (cc == 0)
    		sp = s;
    
    	return sp;
    }
    
    char* har(const char *string, int c) {
    	char *pch = 0;
    
    	while( *string ) {
    		if( *string == c )
    			pch = (char *)string;
    		string++;
    	}
    
    	return (char *)pch;
    }

    Thank you for your time,
    - Stack Overflow
    Last edited by Stack Overflow; 07-06-2004 at 07:01 PM.
    Segmentation Fault: I am an error in which a running program attempts to access memory not allocated to it and core dumps with a segmentation violation error. This is often caused by improper usage of pointers, attempts to access a non-existent or read-only physical memory address, re-use of memory if freed within the same scope, de-referencing a null pointer, or (in C) inadvertently using a non-pointer variable as a pointer.

  11. #26
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by Sebastiani
    The problem with that though is if the string has a length of 0 you will be working with an invalid index (-1).
    Nice catch on that one. Because it is perfectly legal to use the function like so:
    Code:
    foo( "" );


    Which interestingly enough, gives me the following output, in addition to the above:
    foo: 3.32, ""
    bar: 1.7, ""
    baz: 1.44, ""
    qux: 4.08, ""
    zed: 2.27, ""
    It doesn't crash though. So at least that's good. Oddly in this case, strchr beats strrchr.


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

  12. #27
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,006
    Quote Originally Posted by Dave_Sinkula
    When immedaitely following a call to fgets
    Quote Originally Posted by Sebastiani
    The problem with that though is if the string has a length of 0 you will be working with an invalid index (-1).
    I was aware of that. I just hadn't come up with a way of having fgets not return NULL but have an empty string, although I guess I hadn't tried passing it a 1-character "string". An empty line, "\n", will be 1 character long.
    Last edited by Dave_Sinkula; 07-06-2004 at 09:19 PM. Reason: "a empty string" -> "an empty string"
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

  13. #28
    End Of Line Hammer's Avatar
    Join Date
    Apr 2002
    Posts
    6,231
    >>foo( "" );
    >>It doesn't crash though. So at least that's good.
    Lucky more like Modifying string literals is a no no.

    @Stack Overflow: If all you're looking for is a quick way to terminate a string at the first occurence of a particular character (which is what the "strip newline" type functions you've created do), try this:
    Code:
     #include <stdio.h>
     
     void foo(char *s, int c)
     {
       while (*s && *s != c)
       {
         s++;
       }
     
       *s = '\0';
     }
     
     int main(void)
     {
       char  n[] = "blahh\n";
       char  m[] = "\n";
     
       printf("n after >%s<\n", n);
       foo(n, '\n');
       printf("n after >%s<\n", n);
     
       printf("m before >%s<\n", m);
       foo(m, '\n');
       printf("m after >%s<\n", m);
     
       return(0);
     }
    When all else fails, read the instructions.
    If you're posting code, use code tags: [code] /* insert code here */ [/code]

  14. #29
    C Programmer Stack Overflow's Avatar
    Join Date
    Apr 2004
    Posts
    477
    Wow,

    That looks cool. Thanks again, and it looks just like what I needed. (I think)

    Well, this topic has saved me lots of time trying to remove that '\n' out of my sentence. Can't believe I didn't think about a simple 5 liner code:

    Code:
    void foo(char *s, int c) {
    	while (*s && *s != c)
    		s++;
     	*s = '\0';
    }
    And simple too!


    Thanks all for your help,
    - Stack Overflow
    Last edited by Stack Overflow; 07-07-2004 at 06:38 PM.
    Segmentation Fault: I am an error in which a running program attempts to access memory not allocated to it and core dumps with a segmentation violation error. This is often caused by improper usage of pointers, attempts to access a non-existent or read-only physical memory address, re-use of memory if freed within the same scope, de-referencing a null pointer, or (in C) inadvertently using a non-pointer variable as a pointer.

  15. #30
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by Hammer
    >>foo( "" );
    >>It doesn't crash though. So at least that's good.
    Lucky more like Modifying string literals is a no no.
    Actually I'd modified the example to have another line in the array of text being passed it so it had a string like that.
    Code:
    char text[][45] =
       {/* 01234567890123456789012345678901234567890123 */
          "All work and no play makes Jack a dull boy!\n",
          "The quick brown fox jumps over the lazy dog.",
          "",
       };
    Quzah.
    Hope is the first step on the road to disappointment.

Page 2 of 3 FirstFirst 123 LastLast
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Function for removing character from a word
    By TheDeveloper in forum C Programming
    Replies: 6
    Last Post: 07-07-2009, 06:30 AM
  2. character set translation
    By password636 in forum C Programming
    Replies: 1
    Last Post: 06-08-2009, 12:45 PM
  3. Problem using sscanf fgets and overflow checking
    By jou00jou in forum C Programming
    Replies: 5
    Last Post: 02-18-2008, 06:42 AM
  4. Mac - Default Lines Endings - fgets() - no worky
    By Dino in forum C Programming
    Replies: 6
    Last Post: 01-30-2008, 11:59 PM
  5. mygets
    By Dave_Sinkula in forum C Programming
    Replies: 6
    Last Post: 03-23-2003, 07:23 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21