[英]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。
阻止代碼工作的問題是o
和c
容器的大小不匹配,以及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
小問題:
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 = 0
而i < 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.