简体   繁体   English

在不使用任何库 function 的情况下反转字符串

[英]Reversing a string without using any library function

So I want to write a program which will reverse a string taken from the user.所以我想编写一个程序来反转从用户那里获取的字符串。

Here's my source code:这是我的源代码:

#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);
}

But the printed output is nothing!但是打印出来的 output 什么都不是!

Can someone please point out what's wrong with my code?有人可以指出我的代码有什么问题吗?

what's wrong with my code!我的代码有什么问题!

Key functional problems include:关键功能问题包括:

To read "12345\n" with fgets() takes at least 6 bytes, 7 better 1 .fgets()读取"12345\n"至少需要 6 个字节,7 个更好1

Missing null character on o[] o[]上缺少 null 字符

With fgets(c, n, stdin) , c[n-1] is a null character and with "reversing", as code assumes n characters, c[n-1] becomes o[0] and so code prints the empty string.使用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';

Other minor issues exist.存在其他小问题。


1 Increase allocation too and then lop off \n from input. 1也增加分配,然后从输入中删除 \n。

The issue that prevents the code from working is the missmatch in the size of o and c containers, and the read size in fgets , since fgets null-terminates the string read from input.阻止代码工作的问题是oc容器的大小不匹配,以及fgets中的读取大小,因为fgets以空值终止从输入读取的字符串。

So let's say n = 6 as you read your string, fgets replaces the 6th character with a null-terminator, when you reverse it the null-terminator will now be the first character in o , essentially, it will be an empty string, as a string is a null-terminated char-array, or byte-array.因此,假设n = 6在您读取字符串时, fgets 用空终止符替换第 6 个字符,当您反转它时,空终止符现在将成为o中的第一个字符,本质上,它将是一个空字符串,如字符串是以 null 结尾的字符数组或字节数组。

To fix this give fgets the size of your mallocced space.要解决此问题,请给 fgets 分配空间的大小。

fgets(c, n + 1, stdin);

And null-terminate o when you are finished reversing.并在您完成反转时终止o

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

Or或者

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

Minor issues:小问题:

  • The fact that you switch the names of main arguments.您切换主要 arguments 的名称的事实。 It normally is int main(int argc, char * argv[]) .它通常是int main(int argc, char * argv[]) That can be confusing for someone who reads your code.这可能会让阅读您的代码的人感到困惑。
  • char *c = malloc((sizeof(char) * n) + 1); has unnecessary logic, it can be char *c = malloc(n + 1);有不必要的逻辑,可以是char *c = malloc(n + 1); , a char is one byte in size. , char大小为一个字节。
  • There is an underlying problem with the logic of the program, when the inputed string is shorter than what you ask the user the outupt will not be the desired one, you can make an extra effort bullet-proofing your code for erroneous inputs.程序的逻辑存在一个潜在的问题,当输入的字符串比您要求用户输出的字符串短时,输出将不是您想要的,您可以付出额外的努力来防止您的代码出现错误输入。

All things considered, taking your code as base, it can be something like:考虑到所有因素,以您的代码为基础,它可能类似于:

//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
    //...

There are multiple problems in your program:您的程序中存在多个问题:

  • why do you require an argument for the number of characters?为什么需要字符数的参数? it would be much simpler to assume a maximum length and define char arrays in main() with automatic storage.假设最大长度并在main()中使用自动存储定义char arrays 会简单得多。

  • the statement char *c = malloc((sizeof(char) * n) + 1);语句char *c = malloc((sizeof(char) * n) + 1); computes the correct allocation size, but by chance because sizeof(char) is always 1 .计算正确的分配大小,但偶然因为sizeof(char)总是1 You should write char *c = malloc(n + 1);你应该写char *c = malloc(n + 1); or char *c = malloc(sizeof(*c) * (n + 1));char *c = malloc(sizeof(*c) * (n + 1)); . .

  • since fgets() will store the newline, you should increase the allocation size by 1 to avoid leaving the newline in the input stream, but you will need to avoid including the newline in the characters to reverse.由于fgets()将存储换行符,您应该将分配大小增加 1 以避免在输入 stream 中留下换行符,但您需要避免在要反转的字符中包含换行符。 In all cases, you must pass the size of the array to fgets() , not n because fgets() would then only store n - 1 bytes into the array and set c[n - 1] to a null terminator, which causes the reversed string to start with a null terminator, making it an empty string.在所有情况下,您必须将数组的大小传递给fgets() ,而不是n因为fgets()只会将n - 1个字节存储到数组中并将c[n - 1]设置为 null 终止符,这会导致反转字符串以 null 终止符开头,使其成为空字符串。

  • you do not test if fgets() succeeded at reading standard input.您不测试fgets()是否成功读取标准输入。

  • you do not compute the number of characters to reverse.您不计算要反转的字符数。 If the user entered fewer characters than n , you will transpose bytes beyond those that were entered, possibly null bytes which will make the reversed string empty (this is a good explanation for what you observe).如果用户输入的字符少于n ,您将转置超出输入的字节,可能是 null 字节,这将使反转的字符串为空(这是对您观察到的内容的一个很好的解释)。

  • the transposition loop should iterate for i = 0 while i < n , not n + 1 .转置循环应该迭代i = 0i < n ,而不是n + 1

  • you do not set the null terminator at the end of the destination array.您没有在目标数组的末尾设置 null 终止符。 This array is allocated with malloc() , so it is uninitialized.这个数组是用malloc()分配的,所以它是未初始化的。

Here is a modified version:这是修改后的版本:

#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;
}

It is also possible that you run your program from the IDE on a system that closes the terminal window as soon as the program terminates.也可以在程序终止后立即关闭终端 window 的系统上从 IDE 运行程序。 This would prevent you from seeing the output.这会阻止您看到 output。 Add a getchar();添加一个getchar(); before the return 0; return 0; to fix this problem or run the program manually from a shell window.要解决此问题或从 shell window 手动运行程序。

your program will fail if the value n does not match the number of characters in the input string mainly because you do not initialize the memory that you allocate.如果值 n 与输入字符串中的字符数不匹配,您的程序将失败,主要是因为您没有初始化您分配的 memory。

e.g.

n = 10
c = "hello"  

length of c is 5 but you have allocated 11 bytes, so the bytes after hello\n\0 are uninitialized in c since fgets will not fill those out for you. c 的长度为 5,但您已分配 11 个字节,因此 hello\n\0 之后的字节在 c 中未初始化,因为 fgets 不会为您填写这些字节。

in memory it looks something like this在 memory 它看起来像这样

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

when you turn the string around with当你用

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

since you are using n as offset to start copying characters, you start beyond "hello\n\0" copying position 9 (10 - 1 - 0) and placing this as first character in o , but since all of c is not initialized anything can be there, also even a \0 which could explain why you don't print anything.由于您使用n作为偏移量来开始复制字符,因此您开始超出 "hello\n\0" 复制 position 9 (10 - 1 - 0) 并将其作为第一个字符放在o中,但是由于所有c都没有初始化任何东西可以在那里,甚至还有一个\0可以解释为什么你不打印任何东西。

better is to once you read the string calculate the length of the string with a simple for loop更好的是,一旦你读取了字符串,就用一个简单的 for 循环计算字符串的长度

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

and then use len as the offset instead of n然后使用len作为偏移量而不是n

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM