繁体   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