2012-01-27 118 views
0

所以我对C不是很好,但是我设计了一个读取不区分大小写的文件的GLUT应用程序。为了更容易,我想将我的字符串转换为全部小写字母。我做了一个函数makeLower,它正在修改一个通过引用传入的变量。隐藏未知长度的字符串到小写问题

我在makeLower方法中有一个While循环,它似乎通过while循环的第一次迭代的一部分,然后EXE崩溃。任何提示都会很棒,谢谢!

输出:

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 # 

然后错误 “项目的1.exe已停止工作”

代码:

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(); 
} 
+0

你有没有试过在调试器中运行它?除此之外,我可以给你一个提示:你知道指针间接运算符('*')做什么,例如在表达式'* input [i]'中?我建议你看看所有这些。 :) – 2012-01-27 07:07:54

+0

它不尊重变量吗?既然它是通过引用传递给函数的?我对C tbh不太了解。 – meriley 2012-01-27 07:16:58

+1

如果你有一个字符串(指向char的指针),你可以通过使用'string [i]'来获得单个字符,其中'i'是一个介于0和字符串长度之间的数字减1,或者*(字符串+我)'。后者实际上是编译器将'string [i]'转换为的内容。 – 2012-01-27 07:28:21

回答

3

我现在看到更多的问题,所以我向我的评论答案:

您分配的50个字符数组,但告诉fgets获得最多100个字符,这可能是致命的,因为fgets将覆盖不在字符串中的内存。

将C字符串传递给函数时,不必将指针的地址传递给字符串(&lineStr),实际的指针或数组就可以。这意味着您可以将makeLower功能更改为void makeLower(char *input)void makeLower(char input[])。现在,makeLower的参数被声明为数组或char指针,而不是指向char数组的指针。

在新makeLower我上面提出的,您可以访问单个字符是作为数组(input[i]),或者作为一个指针加偏移(*(input + i)。就像我在我的评论说,最后的版本是什么,编译器可能会创建如果你使用的第一,但第一是更具可读性,所以我建议

此外,在makeLower你与"\0"的比较,这是一个字符串,而不是一个字符时,这几乎是正确的实际:你应该使用input[i] != '\0'

最后这是我如何实现它:

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

有关功能的一些解释:

  • 所有字符数组可以被转换为一个字符指针,而不是周围的其他方法。正如您从接受字符串的所有标准函数(如strlenstrcpy)中看到的那样,传递字符指针是实际传递字符串的最常见方式。)
  • 表达式*input解除引用(即,取指针指向的值)字符串。它与*(input + 0)相同,因此得到字符串中第一个字符的值。
  • 虽然字符串中的第一个字符不是'\0'(技术上这是一个正常的零),但我们将循环。
  • 获取字符串的第一个字符并将其传递给tolower函数。无论字符是什么,这都会起作用,tolower只会将大写字符变成小写字母,所有其他字符都会像原来一样返回。
  • tolower的结果复制到第一个字符上。这是有效的,因为分配的右侧必须在分配之前执行,所以不会有任何错误或问题。
  • 最后我们增加一个指针。这将使input指向字符串中的下一个字符。这是可行的,因为input是一个局部变量,因此指针上的操作不会影响调用函数中的任何内容。

此功能现在可以这样调用:据我了解的东西

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

当谈到引用等时,我对C非常可怕。你的帖子解决了我的问题,超级启发!有了这个解释,我认为不应该有任何关于传递的问题。特别是用字符串。谢谢。 – meriley 2012-01-27 09:14:21

0

我认为这个问题是你不知道的当你想要它时,字符串将等于'\ 0'。所以你可能会走出界限,很可能你不知道字符串的长度。

+0

它的第一次迭代甚至没有完成。字符是# 只是该行的第一个字符。下一个输出应该说'Character is d' – meriley 2012-01-27 07:13:31

+0

然后我认为Joachim可能是正确的,因为我知道在C++中使用数组操作符符号会自动解引用一个指针。 – emschorsch 2012-01-27 07:15:17

1

你尝试while(* input [i]!=“\ 0”)而不是你有什么?出于某种原因,您似乎将指向char(* input [])的指针传递给函数,因此在检查字符串终止符字符“\ 0”时解除引用两次会有意义...。

只是一个想法,希望它有助于

0

,它的罚款通过“\ 0”到tolower()。这是一个有效的unsigned char值,而tolower()只是返回输入字符,如果它不能进行任何转换。

因此,循环可以简洁地把为:

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

这确实多了一个呼叫tolower(),但它是短(IMO)很清楚。只是想提出它作为替代。