2012-01-27 123 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)很清楚。只是想提出它作爲替代。