Reputation: 67
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?
Upvotes: 1
Views: 404
Reputation: 153358
what's wrong with my code!
Key functional problems include:
To read "12345\n"
with fgets()
takes at least 6 bytes, 7 better1.
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.
Upvotes: 2
Reputation: 23802
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:
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.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
//...
Upvotes: 2
Reputation: 36082
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)
Upvotes: 1
Reputation: 144695
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.
Upvotes: 2