简体   繁体   中英

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!

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 .

Missing null character on o[]

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

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.

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.

To fix this give fgets the size of your mallocced space.

fgets(c, n + 1, stdin);

And null-terminate o when you are finished reversing.

*(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. It normally is 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); , a char is one byte in size.
  • 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.

  • the statement char *c = malloc((sizeof(char) * n) + 1); computes the correct allocation size, but by chance because sizeof(char) is always 1 . You should write char *c = malloc(n + 1); or 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. 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.

  • you do not test if fgets() succeeded at reading standard input.

  • 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).

  • the transposition loop should iterate for i = 0 while i < n , not n + 1 .

  • you do not set the null terminator at the end of the destination array. This array is allocated with malloc() , so it is uninitialized.

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. This would prevent you from seeing the output. Add a getchar(); before the return 0; to fix this problem or run the program manually from a 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.

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.

in memory it looks something like this

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

better is to once you read the string calculate the length of the string with a simple for loop

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

and then use len as the offset instead of n

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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