[英]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.