簡體   English   中英

在不使用任何庫 function 的情況下反轉字符串

[英]Reversing a string without using any library function

所以我想編寫一個程序來反轉從用戶那里獲取的字符串。

這是我的源代碼:

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

int main(int argv, char *argc[]) {
    if (argv != 2) {
        printf("Please enter the number of elements in your string!\n");
        return 1;
    }
    int n = atoi(argc[1]);
    char *c = malloc((sizeof(char) * n) + 1);
    char *o = malloc((sizeof(char) * n) + 1);
    printf("Enter your string - ");
    fgets(c, n, stdin);
    for (int i = 0; i < n + 1; i++) {
        *(o + i) = *(c + (n - 1) - i);
    }
    printf("%s\n", o);
    free(c);
    free(o);
}

但是打印出來的 output 什么都不是!

有人可以指出我的代碼有什么問題嗎?

我的代碼有什么問題!

關鍵功能問題包括:

fgets()讀取"12345\n"至少需要 6 個字節,7 個更好1

o[]上缺少 null 字符

使用fgets(c, n, stdin)c[n-1]null 字符,並且使用“反轉”,因為代碼假定n字符, c[n-1]變為o[0] ,因此代碼打印空字符串.

  // fgets(c, n, stdin);  // too small
  fgets(c, n + 1, stdin);  

  // add before printing.
  o[n] = '\0';

存在其他小問題。


1也增加分配,然后從輸入中刪除 \n。

阻止代碼工作的問題是oc容器的大小不匹配,以及fgets中的讀取大小,因為fgets以空值終止從輸入讀取的字符串。

因此,假設n = 6在您讀取字符串時, fgets 用空終止符替換第 6 個字符,當您反轉它時,空終止符現在將成為o中的第一個字符,本質上,它將是一個空字符串,如字符串是以 null 結尾的字符數組或字節數組。

要解決此問題,請給 fgets 分配空間的大小。

fgets(c, n + 1, stdin);

並在您完成反轉時終止o

*(o + n) = '\0';

或者

o[n] = '\0'; //you can use this notation which is more readable than dereferencing

小問題:

  • 您切換主要 arguments 的名稱的事實。 它通常是int main(int argc, char * argv[]) 這可能會讓閱讀您的代碼的人感到困惑。
  • char *c = malloc((sizeof(char) * n) + 1); 有不必要的邏輯,可以是char *c = malloc(n + 1); , char大小為一個字節。
  • 程序的邏輯存在一個潛在的問題,當輸入的字符串比您要求用戶輸出的字符串短時,輸出將不是您想要的,您可以付出額外的努力來防止您的代碼出現錯誤輸入。

考慮到所有因素,以您的代碼為基礎,它可能類似於:

//Only the changed parts are represented, the rest is the same
#include <string.h> //for strlen
    //...
    if (argc != 2 || atoi(argv[1]) < 1) { //n must be positive (I switched argv and argc)
        printf("Please enter the number of elements in your string!\n");
        return 1;
    }

    size_t n = atoi(argv[1]); //size_t type more suited for sizes
    char *c = malloc(n + 1);
    char *o = malloc(n + 1);
    //...
    fgets(c, n + 1, stdin);   //as stated n + 1 size argument 

    if(strlen(c) < n) {    //if the length of inputed string is shorter than intended
        puts("The string size shorter than stated!");
        return 1;
    }
    //...
    for (size_t i = 0; i < n + 1; i++) { //repalced int iterator type whith size_t
    //...
    o[n] = '\0'; //null terminate o
    //...

您的程序中存在多個問題:

  • 為什么需要字符數的參數? 假設最大長度並在main()中使用自動存儲定義char arrays 會簡單得多。

  • 語句char *c = malloc((sizeof(char) * n) + 1); 計算正確的分配大小,但偶然因為sizeof(char)總是1 你應該寫char *c = malloc(n + 1); char *c = malloc(sizeof(*c) * (n + 1)); .

  • 由於fgets()將存儲換行符,您應該將分配大小增加 1 以避免在輸入 stream 中留下換行符,但您需要避免在要反轉的字符中包含換行符。 在所有情況下,您必須將數組的大小傳遞給fgets() ,而不是n因為fgets()只會將n - 1個字節存儲到數組中並將c[n - 1]設置為 null 終止符,這會導致反轉字符串以 null 終止符開頭,使其成為空字符串。

  • 您不測試fgets()是否成功讀取標准輸入。

  • 您不計算要反轉的字符數。 如果用戶輸入的字符少於n ,您將轉置超出輸入的字節,可能是 null 字節,這將使反轉的字符串為空(這是對您觀察到的內容的一個很好的解釋)。

  • 轉置循環應該迭代i = 0i < n ,而不是n + 1

  • 您沒有在目標數組的末尾設置 null 終止符。 這個數組是用malloc()分配的,所以它是未初始化的。

這是修改后的版本:

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

int main(int argv, char *argc[]) {
    if (argv != 2) {
        printf("Please enter the maximum number of characters in your string!\n");
        return 1;
    }
    int n = atoi(argc[1]);
    if (n < 1) {
        printf("Invalid number of characters: %d\n", n);
        return 1;
    }
    // allocate 1 extra byte for the newline, one more for the null terminator
    char *buf = malloc(n + 2);
    char *out = malloc(n + 2);
    printf("Enter your string: ");
    if (!fgets(buf, n + 2, stdin)) {
        printf("no input\n");
        return 1;
    }
    // get the number of characters in the input before the newline, if any
    int len;
    for (len = 0; buf[len] && buf[len != '\n'; n++)
        continue;
    // if you can use the library function `strcspn()`, replace the for loop with this:
    //len = strcspn(buf, "\n");

    // copy the string in reverse order
    for (int i = 0; i < len; i++) {
        out[i] = buf[len - 1 - i];
    }
    // set the null terminator
    out[len] = '\0';
    printf("%s\n", out);
    free(buf);
    free(out);
    return 0;
}

也可以在程序終止后立即關閉終端 window 的系統上從 IDE 運行程序。 這會阻止您看到 output。 添加一個getchar(); return 0; 要解決此問題或從 shell window 手動運行程序。

如果值 n 與輸入字符串中的字符數不匹配,您的程序將失敗,主要是因為您沒有初始化您分配的 memory。

e.g.

n = 10
c = "hello"  

c 的長度為 5,但您已分配 11 個字節,因此 hello\n\0 之后的字節在 c 中未初始化,因為 fgets 不會為您填寫這些字節。

在 memory 它看起來像這樣

    +---+---+---+---+---+---+---+---+---+---+---+
c ->| h | e | l | l | o |\n |\0 |   |   |   |   |
    +---+---+---+---+---+---+---+---+---+---+---+

當你用

*(o + i) = *(c + n - 1 - i)

由於您使用n作為偏移量來開始復制字符,因此您開始超出 "hello\n\0" 復制 position 9 (10 - 1 - 0) 並將其作為第一個字符放在o中,但是由於所有c都沒有初始化任何東西可以在那里,甚至還有一個\0可以解釋為什么你不打印任何東西。

更好的是,一旦你讀取了字符串,就用一個簡單的 for 循環計算字符串的長度

int len = 0;
for (len = 0; c[len] && c[len] != '\n'; ++len);

然后使用len作為偏移量而不是n

*(o + i) = *(c + len - 1 + i)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM