2016-01-24 75 views
2

此代碼應該用作vigenere密碼。但是,在運行時,無論您輸入什麼輸入,它都會出現分段錯誤。我正在爲edx在線CS50課程寫這篇文章。是否strncpy應該阻止分段錯誤發生,如果我告訴它複製適當的字符數量?在c中使用strncpy時出現分段錯誤

#include <stdio.h> 
#include <stdlib.h> 
#include <cs50.h> 
#include <string.h> 
#include <ctype.h> 

int main(int argc, string argv[]) { 
    int result; 

    if (argc != 2) { 
     printf("Shame on you!\n"); 
     return 1; 
    } 

    string key = argv[1]; 
    string text = GetString(); 
    string cpy_key = NULL; 

    //strncpy(cpy_key, key, strlen(key)); 
    for (int i = 0, n = strlen(text); i < n; i++) { 
     strcat(cpy_key, key); 
    } 
    cpy_key[strlen(text)] = '\0'; 
    // Main loop starts here 
    for (int i = 0, n = strlen(text); i < n; i++) { 
     result = text[i] + cpy_key[i]; 

     if (isupper(text[i]) && (result > 'Z')) { 
      result = result - 26; 
     } 
     if (islower(text[i]) && (result > 'z')) { 
      result = result - 26; 
     } 
     if (isalpha(text[i])) { 
      printf("%c", result); 
     } else { 
      printf("%c", text[i]); 
     } 
    } 
    printf("\n"); 
    return 0; 
} 
+1

你爲什麼使用'strncpy()'?使用'strcpy()'或者如果你知道目標緩衝區的長度和源緩衝區的長度,確實也使用'memcpy()',除非字符串在循環內部改變,否則不要在循環中使用'strlen()'。 –

+0

@iharob使用strcpy()仍然會導致分段錯誤。此外,strlen()僅在循環開始時被調用一次,並且被保存爲int n。 – Fluffy

+0

在llp開始的時候這樣做,它在我看來就像是'for'的條件。你在Linux上嗎?或者mac?如果是這樣,我建議[valgrind](http://www.valgrind.org),它應該可以幫助你快速發現問題。 –

回答

0

你並不需要做的key副本,你可以索引key模長度。

順便說一句,你應該永遠不要strncpy,它不會做你認爲它,它的語義是容易出錯,這是從來沒有爲工作的工具。最後一個參數應該是目標數組的大小,但是如果源太大,目標將不會以null結尾,如果大小很小,目標大,這個函數將浪費時間填充整個目標數組將'\0'字節。不使用strncpy將爲您節省許多錯誤。

另外不幸的是,cs50.h定義爲stringtypedef char *string;。使用這種類型會導致誤導和錯誤,特別是對於瞭解C++的人。只需使用char *,它使得您的代碼更容易被C程序員閱讀。我希望你不需要使用這種類型,隱藏在typedefs後面的指針通常不是一個好主意。

下面是一個簡單的版本:

#include <stdio.h> 
#include <stdlib.h> 
#include <cs50.h> 
#include <string.h> 
#include <ctype.h> 

int main(int argc, char *argv[]) { 
    int result; 

    if (argc != 2) { 
     printf("Shame on you!\n"); // you might want to be more explicit ;-) 
     return 1; 
    } 

    char *key = argv[1]; 
    int klen = strlen(key); 
    char *text = GetString(); 
    if (!text) { 
     /* end of file or read error */ 
     return 1; 
    } 

    // Main loop starts here 
    for (int i = 0, n = strlen(text); i < n; i++) { 
     result = text[i] + key[i % len]; 

     if (isupper((unsigned char)text[i]) && result > 'Z') { 
      result = result - 26; 
     } 
     if (islower((unsigned char)text[i]) && result > 'z') { 
      result = result - 26; 
     } 
     if (isalpha((unsigned char)text[i])) { 
      printf("%c", result); 
     } else { 
      printf("%c", text[i]); 
     } 
    } 
    printf("\n"); 
    return 0; 
} 

提示:您的V @ genere不正確,你應該使用result = text[i] + key[i % len] - 'A';如果key是全部大寫。

+0

這不起作用。它打印一系列不可打印的字符。 – Fluffy

+0

@Fluffy:我修復了崩潰,你應該修正邏輯,我不能猜測你的解密方法應該是什麼,雖然我知道* vigenere *,但你似乎做錯了。 – chqrlie

+0

啊,謝謝。謝謝您的幫助。 – Fluffy

-1

這是C還是C++?在C語言中,你需要在你自己的字符數組(字符串)分配空間:

char *cpy_key = 0 ; 
... 
size_t key_len = strlen (key) + 1 ; // adding space for terminating NULL 
... 
cpy_key = malloc (key_len) ; // add error management here 
... 
strncpy (cpy_key , key , key_len) ; // add error management here 
... 
free (cpy_key) ; // when you don't need it anymore 
+0

請注意,您正在使用分配'key_len'而不是'key_len + 1'字節的細節。這樣創建的字符串不會以null結尾。添加'+ 1'可以讓你終止字符串。隨着分配時間的更長,你不再需要使用'strncpy()',因爲你確保你有足夠的空間('strcpy()'可以)。你也可以使用'memmove()'(或甚至是'memcpy()'),它的長度爲'key_len + 1'。 –

+0

@JonathanLeffler你(再次)是正確的。現在更新我的答案。謝謝 – mauro

3

cs50.h頭定義typedef char *string;。發生

核心轉儲,因爲你複製到一個空指針:

string cpy_key = NULL; 

//strncpy(cpy_key, key, strlen(key)); 
for (int i = 0, n = strlen(text); i < n; i++) { 
    strcat(cpy_key, key); 

無論是strcat()strncpy(),你需要分配存儲空間cpy_key 。在顯示的循環中,如果輸入的字符串爲50個字符,則要將該字符串複製50次,因此您需要分配超過2500個字符才能保證安全。使用strncpy()會正確地完成這項工作 - 只要您分配足夠的空間。

請注意strncpy()不是一個很好用的功能。如果您有一個20 KiB緩衝區並將一個10字節的字符串複製到它中,它會在該字符串後面寫入20470個空字節。如果你有一個50字節的緩衝區,並且你拷貝了75個字節,它會複製50個字節,並且不會讓緩衝區空終止。兩者都不明顯;缺乏保證的空終止使其變得危險。有更糟糕的接口(strncat()是主要候選人 - 長度參數代表什麼?)但不是很多。

你有一些工作要做你的加密算法。

你可以看看Vigenere cipher only works up to until dealing with a space in C — why?看看它可以做什麼。

1

的一個問題是內存即

string cpy_key = NULL;

也就是說,它只是一個沒有尺寸名稱不分配內存。認識到這一點那麼這一定會失敗

strcat(cpy_key, key);

在調用你試圖連接之類的大小與大小沒有一件事一件事。