Thread: Find if string exist in a vector of structs

  1. #16
    Registered User cstryx's Avatar
    Join Date
    Jan 2013
    Location
    Canada
    Posts
    123
    Quote Originally Posted by Matticus View Post
    You mean people like the OP who probably do not understand the nuances of "scanf()"?

    I was not "wrong", I simply chose not to introduce scansets to the OP because I figured it would be beyond their current understanding. On these forums, I try to gauge my advice based on the perceived experience level of the OP, and I usually do a pretty good job of that.

    There's also the fact that "scanf()" is simply not the best tool for the job. Look at the macro trickery you used just to get "scanf()" to safely read a string. That is why I suggested a better tool for the job, which would likely be much easier for the OP to understand.
    I would respectfully disagree... You simply said that scanf() was not capable of reading whitespace.

    >> "one reason is because it will stop reading at any whitespace (so the input can't have any spaces)."

    *it* being the function will not stop reading at any whitespace. That is the usage of the function to which is responsible for that behavior, so the statement is wrong.

    If you chose not to show what I have shown in my example, a better thing to do would be to tell him that it's a little more complex to get it to work with reading whitespace, and omitted the method for doing so.

    And as I said. &arr, is NOT the same thing as &arr[0]/arr. You are passing an improper pointer type to scanf when you do &arr, so that is wrong. char (*)[9] is not the same as char *.

    Quote Originally Posted by Matticus View Post
    Look at the macro trickery you used just to get "scanf()" to safely read a string
    Those macros are helpers and considered optional. They aren't required to do the same thing and get scanf() to safely read the string... You can also do this at runtime and construct the format string, it's just not really an ideal way of doing it if you know the size of the buffer at compile time.
    Last edited by cstryx; 07-05-2015 at 11:20 AM.

  2. #17
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Quote Originally Posted by cstryx View Post
    Code:
    scanf("%[^\n]" STR(MAX_LENGTH) "s", buf);
    You mean
    Code:
        scanf("%" STR(MAX_LENGTH) "[^\n]", buf);

  3. #18
    Registered User cstryx's Avatar
    Join Date
    Jan 2013
    Location
    Canada
    Posts
    123
    Quote Originally Posted by algorism View Post
    You mean
    Code:
        scanf("%" STR(MAX_LENGTH) "[^\n]", buf);
    Yeah, correct. Good catch! Not sure why I left the s in there and misplaced the specifier. I was tired and swapped over from s to [ too quickly I suppose lol.

  4. #19
    Registered User
    Join Date
    May 2010
    Posts
    4,633
    Yeah, good catch indeed, another reason to prefer fgets() over scanf() when dealing with strings and user input since fgets() doesn't require all the voodoo.


    Jim

  5. #20
    Registered User cstryx's Avatar
    Join Date
    Jan 2013
    Location
    Canada
    Posts
    123
    Quote Originally Posted by jimblumberg View Post
    Yeah, good catch indeed, another reason to prefer fgets() over scanf() when dealing with strings and user input since fgets() doesn't require all the voodoo.


    Jim
    That's the reason I would've suggested, but I wouldn't have said that scanf() was not capable of doing (something similar to) what fgets() does in terms of grabbing whitespace. There's still nuances with fgets() though and that '\n' character.

    I would say that the behavior of scanf() being reliant on the format string which may *hide* the majority of the possible issues in terms of what the function actually ends up doing at runtime, is the main issue with it, aside from the underlying cost of the format string parsing within the complexity of the function. Because of the workings being reliant on a string argument, inadvertent effects might be an undesired result. fgets() is just a simple string grabbing function, as long as you know the downsides to the function with the '\n' character.
    Last edited by cstryx; 07-05-2015 at 01:23 PM.

  6. #21
    Registered User
    Join Date
    Jun 2011
    Posts
    4,513
    Quote Originally Posted by cstryx View Post
    Also your code is not proper either. &string1 is wrong. string1 by itself is already the required pointer needed to be passed to the function... string1 and &string1[0] are the same thing semantically, but &string1 is something else...
    That was not "my code". I copied that line of code provided by the OP, and added the width specifier. Perhaps your correction should have been aimed at them.

    Quote Originally Posted by cstryx View Post
    I would respectfully disagree... You simply said that scanf() was not capable of reading whitespace.

    *it* being the function will not stop reading at any whitespace. That is the usage of the function to which is responsible for that behavior, so the statement is wrong.
    Perhaps I could have been more clear. But as I've said, I gauge my advice by the perceived experience of the OP. I felt delving into scansets would only serve to cloud the issue. But technically, you are right.

    Quote Originally Posted by cstryx View Post
    If you chose not to show what I have shown in my example, a better thing to do would be to tell him that it's a little more complex to get it to work with reading whitespace, and omitted the method for doing so.
    I could have. I could also point out to you that if you wanted to demonstrate this, you could have confirmed your code was working correctly before posting it.

    If you're going to nitpick other peoples' posts, at least make sure you don't make any silly mistakes in the process.

  7. #22
    Registered User cstryx's Avatar
    Join Date
    Jan 2013
    Location
    Canada
    Posts
    123
    Quote Originally Posted by Matticus View Post
    That was not "my code". I copied that line of code provided by the OP, and added the width specifier. Perhaps your correction should have been aimed at them.



    Perhaps I could have been more clear. But as I've said, I gauge my advice by the perceived experience of the OP. I felt delving into scansets would only serve to cloud the issue. But technically, you are right.



    I could have. I could also point out to you that if you wanted to demonstrate this, you could have confirmed your code was working correctly before posting it.

    If you're going to nitpick other peoples' posts, at least make sure you don't make any silly mistakes in the process.
    What's wrong with making mistakes, and why should I make sure to avoid it--as a requirement to point out things that I know are invalid elsewhere... ? We're only human. I fail to see the logic in that statement... Programmers here knew what I was getting at, along with what I was trying to prove, and eventually my mistake was corrected, so at this point I see that all the bad angles have been covered by now.

    I admit I didn't see that it was his code to begin with. Either way he'll come across my remark about the differences between those pointer types regardless of who wrote that code. I have no shame in being corrected, but I see some people here have issues with it due to their egos.

    If people always wrote perfect and accurate code, and I can assure you that the majority of programmer's strive for this, whether they are posting code in a forum or writing code for some open source project of their own... Debuggers and other similar tools wouldn't be useful and probably wouldn't exist. Funny enough, the source of my mistake was made through the same process as the mistake that you have made: copying a line of code and neglecting or overlooking the fact that part of it might not be 100% correct even after just a small modification.

    No hard feelings?
    Last edited by cstryx; 07-05-2015 at 03:38 PM.

  8. #23
    Registered User migf1's Avatar
    Join Date
    May 2013
    Location
    Athens, Greece
    Posts
    385
    For me, what should be emphasized is that scanf() is intended for formatted input, and since interactive input is rarely considered formatted (unless for example it's being redirected from the output of another prog) it shouldn't be the top choice for reading interactive input. Especially for reading plain strings.

    fgets() is a better choice in that case, although coding a custom my_gets(char *s, size_t sz) which also rejects the terminating '\n' is pretty trivial.
    "Talk is cheap, show me the code" - Linus Torvalds

  9. #24
    Registered User cstryx's Avatar
    Join Date
    Jan 2013
    Location
    Canada
    Posts
    123
    Quote Originally Posted by migf1 View Post
    For me, what should be emphasized is that scanf() is intended for formatted input, and since interactive input is rarely considered formatted (unless for example it's being redirected from the output of another prog) it shouldn't be the top choice for reading interactive input. Especially for reading plain strings.

    fgets() is a better choice in that case, although coding a custom my_gets(char *s, size_t sz) which also rejects the terminating '\n' is pretty trivial.
    Something like this?
    Code:
    char *fgets2(char *buf, int bufsize, FILE *fp)
    {
      int ch, n = 0;
      if (!buf) return NULL;
      while ((ch = fgetc(fp)) != EOF
             && ch != '\n' && n < bufsize - 1)
      {
        buf[n++] = ch;
      }
      buf[n] = 0;
      return buf;
    }
    Or are you talking about using fgets() internally and junking the '\n' manually?
    Last edited by cstryx; 07-05-2015 at 04:51 PM.

  10. #25
    Registered User migf1's Avatar
    Join Date
    May 2013
    Location
    Athens, Greece
    Posts
    385
    Quote Originally Posted by cstryx View Post
    Something like this?
    ...
    Or are you talking about using fgets() internally and junking the '\n' manually?
    Yeap, something like that. Actually, since we're talking about intercative input, something like the following that uses directly the stdin stream, and which may be also considered as a somewhat safer version of gets()...

    Code:
    char *my_gets( char *s, size_t sz)
    {
        int c;
        size_t i;
    
        /* sanity checks */
        if ( !s ) {
            return NULL;
        }
        if ( sz< 1 ) {
            return s;  /* alternatively, return NULL; */
        }
    
        for (i=0; i < sz-1 && '\n' != (c=getchar()) && EOF != c; i++) {
            s[i] = c;
        }
        s[i] = '\0';
    
        return s;
    }
    "Talk is cheap, show me the code" - Linus Torvalds

  11. #26
    Registered User cstryx's Avatar
    Join Date
    Jan 2013
    Location
    Canada
    Posts
    123
    Quote Originally Posted by migf1 View Post
    Yeap, something like that. Actually, since we're talking about intercative input, something like the following that uses directly the stdin stream, and which may be also considered as a somewhat safer version of gets()...

    Code:
    char *my_gets( char *s, size_t sz)
    {
        int c;
        size_t i;
    
        /* sanity checks */
        if ( !s ) {
            return NULL;
        }
        if ( sz< 1 ) {
            return s;  /* alternatively, return NULL; */
        }
    
        for (i=0; i < sz-1 && '\n' != (c=getchar()) && EOF != c; i++) {
            s[i] = c;
        }
        s[i] = '\0';
    
        return s;
    }
    My preference would be to write a generic one with a FILE * being specified, then perhaps you could write a macro to call that function with stdin as a parameter:
    Code:
    #define fgets2_stdin(buf, bufsize) fgets2(buf, bufsize, stdin)
    More than one way to skin a cat though.

  12. #27
    Registered User migf1's Avatar
    Join Date
    May 2013
    Location
    Athens, Greece
    Posts
    385
    Or even flushing extra chars from stdin...

    Code:
    char *my_gets_flushed( char *s, size_t sz )
    {
        int c;
        size_t i;
    
        /* sanity checks */
        if ( !s ) {
            return NULL;
        }
        if ( sz < 1 ) {
            return s;
        }
    
        for (i=0; i < sz-1 && '\n' != (c=getchar()) && EOF != c; i++) {
            s[i] = c;
        }
    
        if ( '\n' != c && EOF != c ) {
            while ( '\n' != (c=getchar()) && EOF  != c ) {
                /* void */ ;
            }
        }
        s[i] = '\0';
    
        return s;
    }
    EDIT: We were cross-posting.
    Last edited by migf1; 07-05-2015 at 05:07 PM.
    "Talk is cheap, show me the code" - Linus Torvalds

  13. #28
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    fgets() returns NULL if it hits EOF before reading anything. I added a boolean return parameter (a pointer that can optionally be NULL) to return whether or not a newline was found and removed. sz must be > 1
    Code:
    #include <stdio.h>
    #include <string.h>
    
    char *xfgets(char *line, size_t sz, FILE *fin, int *nl_found) {
        int c;
        if (nl_found) *nl_found = 0;
        if (sz < 2 || (c = fgetc(fin)) == EOF)
            return NULL;
        do {
            if (c == '\n') {
                if (nl_found) *nl_found = 1;
                break;
            }
            else
                *line++ = c;
        }while (--sz > 1 && (c = fgetc(fin)) != EOF);
        *line = '\0';
        return line;
    }
    
    int main() {
        char line[2];  // small for testing
        int nl_found = 0;
        while (xfgets(line, sizeof line, stdin, &nl_found)) {
            printf("%s", line);
            if (nl_found) putchar('\n');
        }
        return 0;
    }

  14. #29
    Registered User
    Join Date
    Jun 2011
    Posts
    4,513
    Quote Originally Posted by cstryx View Post
    I have no shame in being corrected, but I see some people here have issues with it due to their egos.
    I don't know if you're including me in that category, but I did acknowledge that your criticism of me not being explicit about "scanf()" was valid.

    Quote Originally Posted by cstryx View Post
    No hard feelings?
    No hard feelings. After all, pedantry is an asset in this community.

  15. #30
    Registered User cstryx's Avatar
    Join Date
    Jan 2013
    Location
    Canada
    Posts
    123
    Quote Originally Posted by algorism View Post
    fgets() returns NULL if it hits EOF before reading anything. I added a boolean return parameter (a pointer that can optionally be NULL) to return whether or not a newline was found and removed. sz must be > 1
    Code:
    #include <stdio.h>
    #include <string.h>
    
    char *xfgets(char *line, size_t sz, FILE *fin, int *nl_found) {
        int c;
        if (nl_found) *nl_found = 0;
        if (sz < 2 || (c = fgetc(fin)) == EOF)
            return NULL;
        do {
            if (c == '\n') {
                if (nl_found) *nl_found = 1;
                break;
            }
            else
                *line++ = c;
        }while (--sz > 1 && (c = fgetc(fin)) != EOF);
        *line = '\0';
        return line;
    }
    
    int main() {
        char line[2];  // small for testing
        int nl_found = 0;
        while (xfgets(line, sizeof line, stdin, &nl_found)) {
            printf("%s", line);
            if (nl_found) putchar('\n');
        }
        return 0;
    }
    Decent

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 4
    Last Post: 07-05-2013, 02:30 AM
  2. Replies: 16
    Last Post: 06-13-2013, 06:15 PM
  3. Comparing a string that might not exist?
    By screennameless in forum C++ Programming
    Replies: 23
    Last Post: 07-16-2011, 12:31 PM
  4. Replies: 7
    Last Post: 06-16-2011, 06:21 PM
  5. Replies: 52
    Last Post: 07-22-2010, 02:12 AM

Tags for this Thread