简体   繁体   English

覆盖未知长度的字符串以解决小写问题

[英]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. 因此,我对C不太满意,但是我正在设计一个GLUT应用程序,该应用程序读取的文件不区分大小写。 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. 我做了一个函数makeLower,该函数正在修改通过引用传递的变量。

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. 我在makeLower方法中有一个While循环,该循环似乎可以通过while循环的第一次迭代的一部分,然后使EXE崩溃。 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" 然后错误“项目1.exe已停止工作”

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. 您分配了一个由50个字符组成的数组,但告诉fgets最多获取100个字符,这可能是致命的,因为fgets会覆盖不在字符串中的内存。

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. 将C字符串传递给函数时,不必将指针的地址传递给字符串( &lineStr ),实际的指针或数组都可以。 This means you can change the makeLower function to void makeLower(char *input) or void makeLower(char input[]) . 这意味着您可以将makeLower函数更改为void makeLower(char *input)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. 现在, makeLower的参数声明为数组或char指针,而不是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. 在上面我提出的新makeLower ,您可以将单个字符作为数组( input[i] )或作为指针加上偏移量( *(input + i) ,就像我在评论中说的那样,最后一个版本是如果您使用第一个,则编译器可能会创建,但是第一个更易读,所以我建议这样做。

Also in makeLower you make a comparison with "\\0" , which is a string and not a character. 同样在makeLower您与"\\0"进行比较, "\\0"是字符串而不是字符。 This is almost right actually: You should use input[i] != '\\0' . 实际上这几乎是正确的:您应该使用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. 可以将所有char数组转换为char指针,但不能相反。 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 .) 传递char指针实际上是传递字符串的最常用方法,正如您从所有接受字符串的标准函数(如strlenstrcpy )中所看到的那样。
  • The expression *input dereferences (ie takes the value of what a pointer points to) the string. 表达式*input 取消引用 (即获取指针指向的值)字符串。 It is the same as *(input + 0) and so get the value of the first character in the string. 它与*(input + 0) ,因此获取字符串中第一个字符的值。
  • While the first character in the string is not '\\0' (which technically is a normal zero) we will loop. 虽然字符串中的第一个字符不是'\\0' (从技术上来说是正常的零),我们将循环播放。
  • Get the first character of the string and pass it to the tolower function. 获取字符串的第一个字符,并将其传递给tolower函数。 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. 无论字符是什么,这都将起作用, tolower只会将大写字符变为小写,所有其他字符将被返回。
  • The result of tolower copied over the first character. 结果tolower复制的第一个字符。 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. 这将使input指向字符串中的下一个字符。 This works because input is a local variable, so operations on the pointer will not affect anything in the calling function. 这是可行的,因为input是局部变量,因此对指针的操作不会影响调用函数中的任何内容。

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 ? 您是否尝试了while(* input [i]!=“ \\ 0”)而不是您拥有的东西? 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".... 由于某种原因,您似乎将指向char(* input [])和&lineStr的指针传递给函数,因此在检查字符串终止符“ \\ 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. 我认为问题是您不希望该字符串等于'\\ 0'。 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() . 据我了解,可以将'\\ 0'传递给tolower() It's a valid unsigned char value, and tolower() simply returns the input character if it is not able to do any conversion. 这是有效的unsigned char值,并且tolower()仅在无法进行任何转换tolower()返回输入字符。

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. 这会再调用一次tolower() ,但它更短,并且(imo)很清楚。 Just wanted to mention it as an alternative. 只是想提一下它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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