2016-12-01 113 views
-1

我正在EDX CS50課程,我應該寫一個C代碼,使用Vigenere密碼加密消息。我做到了。但問題是我不斷收到緩衝區溢出。C - 緩衝區溢出與strcpy()和strncpy()

如果我使用短字符串,如「Meet」,它可以正常工作。但是如果我使用更長的字符串,比如「上午11點在公園與我會面」,我會遇到緩衝區溢出。

如果我使用strcpy()同時複製在argv[1]傳遞到另一個變量鍵(假設k)和原始消息(msg)的加密消息(encMsg)的變量,然後將它刪除了我必須在k 。 如果我再次使用strcpy()argv[1]的值複製到k再一次,我在encMsg連接兩個字符串時發生緩衝區溢出。

如果我使用strccpy(),它將不會獲得k的內容擦除,但它會溢出並連接encMsg上的兩個字符串。

這一切都發生在我使用GetSting()(來自cs50.h);

如果我使用fgets(),那麼我會在msg結尾處得到'\ n',然後必須添加一個if以在'\ n'處放置'\ 0',這解決了我的問題,但我想知道是否有人能解釋我爲什麼會發生這種情況。

這裏是我的代碼:

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


int main(int argc, char *argv[]) 
{ 
    if (argc != 2) //Checks if number of command-line arguments is valid 
    { 
     printf ("usage: ./caesar + key \n"); 
     return 1;  
    } 

    char k[strlen(argv[1])]; 
    //strcpy(k, argv[1]);   //Saves argument into a string 
    strncpy(k, argv[1], strlen(argv[1])); 

    for (int x = 0; x < strlen(k); x++) 
    { 
     if (k[x] < 65 || (k[x] > 90 && k[x] < 97) || k[x] > 122) //Checks if there is any non-alphabetical character in key 
     { 
      printf ("key must contain only alphabetical characters \n"); 
      return 1;  
     } 
    } 

    //printf("Inform the message you want to encrypt: \n"); 
    string msg = GetString(); 
    //char msg[255]; 
    //fgets(msg, 255, stdin); 

    char encMsg[strlen(msg)]; 
    //strcpy(encMsg, msg); 
    strncpy(encMsg, msg, strlen(msg)); 

    //strcpy(k, argv[1]); 

    int y = 0; 
    for (int x = 0; x < strlen(msg); x++) 
    { 
     //if(msg[x] == '\n') msg[x] = '\0'; 
     if (msg[x] < 65 || (msg[x] > 90 && msg[x] < 97) || msg[x] > 122) encMsg[x] = msg[x]; 
     else if ((msg[x] + (k[y] - 97) > 90 && msg[x] + (k[y] - 97) < 97) || msg[x] + (k[y] - 97) > 122) 
     { 
      encMsg[x] = msg[x] + (k[y] - 97) - 26; 
      y++; 
     } 
     else 
     { 
      encMsg[x] = msg[x] + (k[y] - 97); 
      y++; 
     } 
     if (y >= strlen(k)) y = 0; 
    } 

    printf("key  = %s\n", k); 
    printf("msg  = %s\n", msg); 
    printf("encMsg = %s\n", encMsg); 


    return 0; 
} 
+0

'如果(K [X] <65 ||(K [X]> 90 && K [X] <97)|| K [X]> 122)'是有標準C函數的原因,如'isalpha()','isupper()'和'islower()'。 –

+0

哦,非常感謝@Olaf。這是一個非常好的答覆。但下一次,爲自己節省麻煩。 –

+0

@AndrewHenle謝謝,朋友。我對C相當陌生,所以我不知道這些。 –

回答

4

這個代碼風格:

char k[strlen(argv[1])]; 

留下了終止'\0「字符的空間。它應該是

char k[strlen(argv[1]) + 1 ]; 

而且在評論中指出,這樣的代碼

strncpy(k, argv[1], strlen(argv[1])); 

將無法​​正常終止目標字符串。每the standard for strncpy()

如果數組指向s2是一個字符串短於n 字節,NUL字符應陣列 通過s1指出,在被追加到拷貝,直到n字節都是書面。

由於目標串n短,只有源串中的非NUL字節被作爲有他們的n複製。

正確代碼可能是

strncpy(k, argv[1], 1 + strlen(argv[1])); 
+1

否則,''strlen(argv [1])'空間用於終止NUL,但'strncpy(k,argv [1],strlen(argv [1]));'__by definition__不復制NUL字節因爲它不包含在'argv [1]'的第一個'strlen(argv [1])'字節中。 –

+0

@MichaelFoukarakis那也是。我會補充一點。 –