Alex Rivera | Logout

fgets doesn't work after scanf

Asked 2011-05-06T23:37:43.893
22
#include <stdio.h>
#include <string.h>
#include <ctype.h>

void delspace(char *str);

int main() {
    int i, loops;
    char s1[101], s2[101];

    scanf("%d", &loops);

    while (loops--) {
        fgets(s1, 101, stdin);
        fgets(s2, 101, stdin);
        s1[strlen(s1)] = '\0';
        s2[strlen(s2)] = '\0';

        if (s1[0] == '\n' && s2[0] == '\n') {
            printf("YES\n");
            continue;
        }

        delspace(s1);
        delspace(s2);

        for (i = 0; s1[i] != '\0'; i++)
            s1[i] = tolower(s1[i]);

        for (i = 0; s2[i] != '\0'; i++)
            s2[i] = tolower(s2[i]);

        if (strcmp(s1, s2) == 0) {
            printf("YES\n");
        }
        else {
            printf("NO\n");
        }
    }

    return 0;
}

void delspace(char* str) {
    int i = 0;
    int j = 0;
    char sTmp[strlen(str)];

    while (str[i++] != '\0') {
        if (str[i] != ' ') {
            sTmp[j++] = str[i];
        }
    }
    sTmp[j] = '\0';
    strcpy(str, sTmp);
}

After I entered "loops", "s1" was assigned a blank line automatically. How does it happen? I'm sure my keyboard works fine.

Edit
Report

1 Answer

1

Geekosaur has answered your question well, I'm just pointing out another "problem" with your code.

The line s1[strlen(s1)] = '\0'; is a no-op if s1 is already properly null terminated BEFORE it executes.

But if s1 is NOT already properly null-terminated BEFORE this line executes (and you're unlucky) it will cause:

  • a SIGSEGV on a POSIX (*nix) system.
  • a GPF on Windows.

This is because strlen basicaly finds the index of the existing null-terminator and returns it! Here's a valid, unoptimized implementation of strlen:

int strlen(char *string) {
    int i = 0;
    while(string[i] != '\0') {
        ++i;
    }
    return i;
}

So... If you're REALLY worried about strings NOT being null-terminated then you'd do something like:

  • string[sizeof(string)]='\0'; on local automatic strings (where the compiler "knows" the size of the string);
  • or string[SIZE_OF_STRING] for all other strings, where SIZE_OF_STRING is (most commonly) a #define'd constant, or a variable which you maintain specifically to store the current-SIZE (not length) of a dynamically allocated string.

And if you're REALLY, REALLY, REALLY worried about strings not being null-terminated (like you're dealing with "dirty" libary methods (like Tuxedo's ATMI for example) you ALSO "clear" your "return strings" before passing them to the suspect library m

answered 2011-05-07T00:29:05.873

Your Answer