简体   繁体   中英

Coverting an unknown length string to lower case issues

So I'm not very good with C but I'm designing a GLUT application that reads in a file that is not case sensitive. To make it easier I want to convert my strings to all lower case. I made a function makeLower that is modifying a variable that was passed in by reference.

I have a While Loop in the method makeLower that seems to get through part of the first iteration of the while loop and then the EXE crashes. Any tips would be great, thanks!

Output:

C:\Users\Mark\Documents\Visual Studio 2010\Projects\Project 1\Debug>"Project 1.e
xe" ez.txt

Line is #draw a diamond ring

Character is #

Then error "project 1.exe has stopped working"

Code:

void makeLower(char *input[]){
    int i = 0;
    printf("Line is %s\n", *input);

    while(input[i] != "\0"){
        printf("Character is %c\n", *input[i]); 
        if(*input[i] >= 'A' && *input[i] <= 'Z'){
            *input[i] = tolower(*input[i]);
        }
        i++;
    }

}

int main(int argc, char *argv[]) {
    FILE *file = fopen(argv[1], "r");
    char linebyline [50], *lineStr = linebyline;
    char test;

    glutInit(&argc, argv);

    while(!feof(file) && file != NULL){
        fgets(lineStr , 100, file);
        makeLower(&lineStr);
        printf("%s",lineStr);

        //directFile();

    }
    fclose(file);


    glutMainLoop();
}

I see more problems now, so I extend my comments to an answer:

You allocate an array of 50 characters, but tell fgets to get up to 100 characters, which might be fatal as fgets will overwrite memory not in the string.

When passing a C string to a function, you don't have to pass the address of the pointer to the string ( &lineStr ), the actual pointer or array is okay. This means you can change the makeLower function to void makeLower(char *input) or void makeLower(char input[]) . Right now the argument to makeLower is declared as an array or char pointers, not a pointer to an array of char.

In the new makeLower I proposed above, you can access single characters either as an array ( input[i] ) or as a pointer plus offset ( *(input + i) . Like I said in my comment, the last version is what the compiler will probably create if you use the first. But the first is more readable so I suggest that.

Also in makeLower you make a comparison with "\\0" , which is a string and not a character. This is almost right actually: You should use input[i] != '\\0' .

And finally this is how I would implement it:

void makeLower(char *input)
{
    while (*input != '\0')  /* "while (*input)" would also work */
    {
        *input = tolower(*input);
        input++;
    }
}

A few explanations about the function:

  • All char arrays can be converted to a char pointer, but not the other way around. Passing char pointer is the most common way to pass a string actually, as you can see from all standard functions that accepts strings (like strlen or strcpy .)
  • The expression *input dereferences (ie takes the value of what a pointer points to) the string. It is the same as *(input + 0) and so get the value of the first character in the string.
  • While the first character in the string is not '\\0' (which technically is a normal zero) we will loop.
  • Get the first character of the string and pass it to the tolower function. This will work no matter what the character is, tolower will only turn upper case characters to lower case, all other characters will be returned as they already were.
  • The result of tolower copied over the first character. This works because the right hand side of an assignment must be executed before the assignment, so there will not be any error or problem.
  • Last we increase the pointer by one. This will make input point to the next character in the string. This works because input is a local variable, so operations on the pointer will not affect anything in the calling function.

This function can now be called like this:

char input[100];
fgets(input, sizeof(input), stdin);
printf("before: \"%s\"\n", input);
makeLower(input);
printf("after : \"%s\"\n", input);

Did you try while(*input[i] != "\\0") instead of what you have ? For some reason you seem to pass to your function a pointer to pointer to char (*input[]) and &lineStr so it would make sense to dereference twice when you check for string terminator character "\\0"....

Just a thought, hope it helps

I think the problem is that you don't know that the string is going to equal '\\0' when you want it to. So you may be going out of bounds which is very likely that you don't know the length of the string.

As far as I understand things, it's fine to pass '\\0' to tolower() . It's a valid unsigned char value, and tolower() simply returns the input character if it is not able to do any conversion.

Thus, the loop can be succinctly put as:

while(input[i] = tolower(input[i]))
  ++i;

This does one more call to tolower() , but it's shorter and (imo) quite clear. Just wanted to mention it as an alternative.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM