Print a string reversed in C - c

I'm coding a program that takes some files as parameters and prints all lines reversed. The problem is that I get unexpected results:
If I apply it to a file containing the following lines
one
two
three
four
I get the expected result, but if the file contains
september
november
december
It returns
rebmetpes
rebmevons
rebmeceds
And I don't understand why it adds a "s" at the end
Here is my code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void reverse(char *word);
int main(int argc, char *argv[], char*envp[]) {
/* No arguments */
if (argc == 1) {
return (0);
}
FILE *fp;
int i;
for (i = 1; i < argc; i++) {
fp = fopen(argv[i],"r"); // read mode
if( fp == NULL )
{
fprintf(stderr, "Error, no file");
}
else
{
char line [2048];
/*read line and reverse it. the function reverse it prints it*/
while ( fgets(line, sizeof line, fp) != NULL )
reverse(line);
}
fclose(fp);
}
return (0);
}
void reverse(char *word)
{
char *aux;
aux = word;
/* Store the length of the word passed as parameter */
int longitud;
longitud = (int) strlen(aux);
/* Allocate memory enough ??? */
char *res = malloc( longitud * sizeof(char) );
int i;
/in this loop i copy the string reversed into a new one
for (i = 0; i < longitud-1; i++)
{
res[i] = word[longitud - 2 - i];
}
fprintf(stdout, "%s\n", res);
free(res);
}
(NOTE: some code has been deleted for clarity but it should compile)

You forget to terminate your string with \0 character. In reversing the string \0 becomes your first character of reversed string. First allocate memory for one more character than you allocated
char *res = malloc( longitud * sizeof(char) + 1);
And the try this
for (i = 0; i < longitud-1; i++)
{
res[i] = word[longitud - 2 - i];
}
res[i] = '\0'; // Terminating string with '\0'

I think I know the problem, and it's a bit of a weird issue.
Strings in C are zero terminated. This means that the string "Hi!" in memory is actually represented as 'H','i','!','\0'. The way strlen etc then know the length of the string is by counting the number of characters, starting from the first character, before the zero terminator. Similarly, when printing a string, fprintf will print all the characters until it hits the zero terminator.
The problem is, your reverse function never bothers to set the zero terminator at the end, which it needs to since you're copying characters into the buffer character by character. This means it runs off the end of your allocated res buffer, and into undefined memory, which just happened to be zero when you hit it (malloc makes no promises of the contents of the buffer you allocate, just that it's big enough). You should get different behaviour on Windows, since I believe that in debug mode, malloc initialises all buffers to 0xcccccccc.
So, what's happening is you copy september, reversed, into res. This works as you see, because it just so happens that there's a zero at the end.
You then free res, then malloc it again. Again, by chance (and because of some smartness in malloc) you get the same buffer back, which already contains "rebmetpes". You then put "november" in, reversed, which is slightly shorter, hence your buffer now contains "rebmevons".
So, the fix? Allocate another character too, this will hold your zero terminator (char *res = malloc( longitud * sizeof(char) + 1);). After you reverse the string, set the zero terminator at the end of the string (res[longitud] = '\0';).

there are two errors there, the first one is that you need one char more allocated (all chars for the string + 1 for the terminator)
char *res = malloc( (longitud+1) * sizeof(char) );
The second one is that you have to terminate the string:
res[longitud]='\0';
You can terminate the string before entering in the loop because you know already the size of the destination string.
Note that using calloc instead of malloc you will not need to terminate the string as the memory gets alreay zero-initialised

Thanks, it solved my problem. I read something about the "\0" in strings but wasn't very clear, which is now after reading all the answers (all are pretty good). Thank you all for the help.

Related

Does using malloc to create a string not automatically add a NULL terminator?

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <math.h>
char* center(char* s, int n){
int len = strlen(s);
size_t newArrayLength = n+1;
char* newString = malloc(newArrayLength); // did not use size of char, as sizeof(char) is 1, I used n+1 to make space for the end of string character
if(newString == NULL){
return("Sorry, could not allocate memory"); //checked allocating memory worked
}
int dashes = n - len; //number of dashes needed
if(dashes < 0){
return "Not have enough dashes!!!!!!!!";
}
int lsdash= (dashes/2); //number of left side dashes
int rsdash = dashes - lsdash; //number of right side dashes
for(int i = 0; i < n; i++){
if(i<lsdash){ // if within the left dash region, place a dash
newString[i] = '-';
}
else if(i>=lsdash && i<len+lsdash){ // if within the string region, write out the string
newString[i] = s[i-lsdash];
}
else{
newString[i] = '-'; // else, we are in the right dash region, so place a dash
}
}
newString[n] = '\0';
return newString;
}
int main(){
char* str = "cat"; //original string I wish to place dashes around
int n = 9; // length of new string, that includes dashes
char* newString = center(str, n);
printf("%s\n", newString);
return 0;
}
The above code is supposed to take a string, in this case cat, and surround it with dashes, so that it is in the middle of all the dashes. At the end of the center function, I have a line which manually adds the null terminator character to the string.
My problem is, without this line of code, sometimes but not all the time, I get a random character at the end of my string. I assume this is because the code is reading memory unrelated to the string as it has not come across an '\0' character. Why does this happen, does using malloc to create a char array not add the '\0' necessary to detect the end of the string? Any help is much appreciated
No, it does not.
The memory allocated from malloc is not guaranteed to be initialized, and reading any part you haven't previously written causes undefined behavior. In particular you certainly cannot rely on having null characters anywhere within it.
The line where you "manually" add the null terminator is necessary. Do not remove it.
The calloc function does promise to initialize the allocated memory with zero bytes. In that case, you can be sure that whatever you wrote will be followed by a null terminator (provided you didn't overwrite the last byte). However, this comes at a runtime cost, and means it unnecessarily initializes many bytes that you will shortly overwrite anyway.

why is my printf doing this?

it seems like such a silly thing to ask but i seriously don't know why this is happening. Could be that it's almost 5am and i'm still doing this but..
It should print -CA but why when i compile it, it is printing
-
CA?
instead of -CA, there isn't a '\n' anywhere in sight.
Can you guys think of anything logical that would explain it?
int main(int argc, char* argv[]){
int check = 0;
char *thing = (char*)malloc(2 * sizeof(char));
strcpy(char, "CA");
some code..
do{
more code...
if(condition== 1) {
more code....
if(check == 0) {
printf("-");
check++;
}
if (some conditon != NULL){
printf("%s\n",thing);
}while(condition)
return 0;
}
You didn't allocate enough space for your string. Every string has a null terminator, so a 2-character string needs 3 bytes in the array. Your strcpy() is writing outside the bounds of the thing array when it copies the null byte, which results in undefined behavior.
Use
char *thing = malloc(3);
You can also use strdup(), which makes a copy of a string in dynamic memory, automatically allocating enough space based on the length of the original string.
char *thing = strdup("CA");
printf prints a null terminated string to the stdout. if the sting is not null terminated the printf will go on printing garbage to the stdout till a null terminator is met
so you should all one to your character array
char thing[3] = {'C','A',0};
now printf will print
-
CA

StrCat is not working with Single Char String - C

I'm using the code below to add some "0" chars into my string, but it seems there is a problem and the program will crash. Everything seems logic but I do not know where is the problem?
#include <stdlib.h>
#include <string.h>
int main()
{
char *Ten; int i=0; Ten = malloc(12);
Ten="1";
for (i=0;i<10;i++)
strcat(Ten,"0");
printf("%s",Ten);
return 0;
}
You declare Ten as a pointer to a string literal. However, you cannot rely on being able to modify a string literal, and thus the program crashes.
To fix this, you can declare Ten as an array instead:
int main()
{
char Ten[12]="1"; int i=0;
for (i=0;i<10;i++)
strcat(Ten,"0");
printf("%s",Ten);
return 0;
}
Note that you need 12 bytes; 11 for the characters and one for the terminating NUL character.
Ten is a string literal and you cannot modify it. Try with array instead
char Ten[12] = "1";
for (i=0;i<10;i++)
strcat(Ten,"0");
printf("%s",Ten);
notice that I created an array of 12 characters, because there should be room for a termination '\0'.
You actually don't need strcat here, it's just do this
char Ten = malloc(12);
if (Ten != NULL)
{
Ten[0] = '1';
for (i = 1 ; i < 11 ; i++)
Ten[i] = '0';
Ten[11] = '\0';
/* Use Ten here, for example printf it. */
printf("%s",Ten);
/* You should release memory. */
free(Ten);
}
or
char Ten = malloc(12);
if (Ten != NULL)
{
Ten[0] = '1';
memset(Ten + 1, '0', 10);
Ten[11] = '\0';
/* Use Ten here, for example printf it. */
printf("%s",Ten);
/* You should release memory. */
free(Ten);
}
To quote from strcat manual on linux:
The strcat() function appends the src string to the dest string,
overwriting the terminating null byte ('\0') at the end of dest, and
then adds a terminating null byte. The strings may not overlap, and
the dest string must have enough space for the result. If dest is not
large enough, program behavior is unpredictable; buffer overruns are
a favorite avenue for attacking secure programs.
Your Ten array is only long enough to store original literal. You need to preallocate memory as long as final desired string.
String literals might be stored in read only section of memory. Any attempt to modify such a literal causes undefined behavior.
To concatenate two strings, the destination must have enough space allocated for the characters to be added and space for '\0'. Change the declaration of Ten to
char Ten[12] = "1";
and it will work.

Need help finding bug, if string input is composed all of same character one output character is corrupt

reverser() reverses a cstring (not in place). 99% of the time it works but some input corrupts it for example it appears if aStr2[] is assigned a string made up of the same character it will have an error.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* reverser(const char *str);
int main()
{
char aStr[] = "aaa";
char aStr2[] = "cccccc";
printf("%s %s", aStr, aStr2);
char* tmp = reverser(aStr2);//tmp now has garbage
printf("\n%s", tmp);
printf(" %s", aStr2);
return 0;
}
char* reverser(const char *str)
{
char* revStr = (char*)malloc(strlen(str));
int i;
for(i = strlen(str)-1; i >= 0; i--)
{
revStr[strlen(str)-1-i] = str[i];
}
return revStr;
}
Gives
aaa cccccc
cccccc9 cccccc
Process returned 0 (0x0) execution time : 0.068 s
Press any key to continue
Notice the 9 that shouldn't be there.
Change this malloc to strlen(str) + 1 , plus 1 for '\0'
char* revStr = (char*)malloc(strlen(str) + 1);
and after the for loop
revStr[strlen(str)+1] = '\0';
Your problem is that you don't put the string terminator in your reversed string. All strings in C are actually one extra character that isn't reported by strlen, and that is the character '\0' (or plain and simple, a zero). This tells all C functions when the string ends.
Therefore you need to allocate space for this extra terminator character in your malloc call, and add it after the last character in the string.
There are also a couple of other problems with your code, the first is that you should not cast the return of malloc (or any other function returning void *). Another that you have a memory leak in that you do not free the memory you allocate. This last point doesn't matter in a small program like the one you have here, but will be an issue in larger and longer running programs.
You haven't null-terminated your reversed string. You need to set the final index of revStr[] to 0.

Concatenating multiple strings?

I am processing an input string, which consists of a process name, followed by an arbitrary amount of arguments.
I need the process name , along with all of the arguments, in one string.
I thought I could use strcat in a loop, so that it cycles through all of the args and each time appends the arg to the string, but I am having problems with getting a string that in empty to begin the loop.
Can anyone help me out with some basic code?
Thanks.
EDIT:
I'm posting my code for clarity. Mike's post is closest to what I have now:
char * temp;
strcpy(temp,"");
for (i = 4; i < argc-1; i++) // last arg is null, so we need argc-1
{
strcat(temp,argv[i]);
strcat(temp," ");
}
ignore the 4 in my for loop for the moment (magic number, i know.)
I am getting a segfault with this code. Is it because of my string assignment? I assume that is the case and hence I asked the question of how i could combine the strings.
Let's say your input strings are in an array of char pointers, suggestively called argv, of length argc.
We first need to determine how much space is needed for the output:
int length = 0;
for (int i = 0; i < argc; ++i)
length += strlen(argv[i]);
Then we allocate it, adding an extra char for the '\0' terminator:
char *output = (char*)malloc(length + 1);
Finally, the concatenation:
char *dest = output;
for (int i = 0; i < argc; ++i) {
char *src = argv[i];
while (*src)
*dest++ = *src++;
}
*dest = '\0';
Note that I don't use strcat here. Reason is that this sets us up for a Schlemiel the Painter's algorithm: for each iteration, the entire output string would be scanned to find its end, resulting in quadratic running time.
Don't forget to free the output string when you're done:
free(output);
I'm a bit tired so I may be overlooking something here. A better solution, using standard library functions, is welcome. It would be convenient if strcat returned a pointer to the terminator byte in dest, but alas.
You want an empty C string? Is this what you are looking for: char p[] = "";?
UPDATE
After you posted some code it is clear that you have forgotten to allocate the buffer temp. Simply run around the arguments first, counting up the length required (using strlen), and then allocate temp. Don't forget space for the zero terminator!
You could provide the "arbitrary amount of arguments" as one argument, ie an array/list, then do this pseudocode:
str = "";
i = 0;
while i < length of input
{
str = strcat ( str , input[i]);
i++;
}
#include<stdio.h>
#include<stdarg.h>
int main(int argc, char** argv) {
// the main parameters are the same situation you described
// calling this program with main.exe asdf 123 fdsa, the program prints out: asdf123fdsa
int lengths[argc];
int sum =0;
int i;
for(i=1; i<argc; i++) { // starting with 1 because first arg is program-path
int len = strlen(argv[i]);
lengths[i] = len;
sum+=len;
}
char* all = malloc(sum+1);
char* writer = all;
for(i=1; i<argc; i++) {
memcpy(writer, argv[i], lengths[i]);
writer+=lengths[i];
}
*writer = '\0';
printf("%s\n", all);
system("pause");
return 0;
}
A string in C is represented by an array of characters that is terminated by an "null" character, '\0' which has the value 0. This lets all string functions know where the end of a string is. Here's an exploration of different ways to declare an empty string, and what they mean.
The usual way of getting an empty string would be
char* emptyString = "";
However, emptyString now points to a string literal, which cannot be modified. If you then want to concatenate to an empty string in your loop, you have to declare it as an array when you initialize.
char buffer[] = "";
This gives you an array of size one. I.e. buffer[0] is 0. But you want an array to concatenate to- it has to be large enough to accomodate the strings. So if you have a string buffer of certain size, you can initialize it to be empty like so:
char buffer[256] = "";
The string at buffer is now "an empty string". What it contains, is buffer[0] is 0 and the rest of the entries of the buffer might be garbage, but those will be filled once you concatenate your other strings.
Unfortunately, the problem with C, is you can never have an "infinite" string, where you are safe to keep concatenating to, you have to know it's definite size from the start. If your array of arguments are also strings, you can find their length using strlen. This gives you the length of a string, without the null character. Once you know the lengths of all your sub-strings, you will now know how long your final buffer will be.
int totalSize; // assume this holds the size of your final concatenated string
// Allocate enough memory for the string. the +1 is for the null terminator
char* buffer = malloc(sizeof(char) * (totalSize + 1));
buffer[0] = 0; // The string is now seen as empty.
After this, you are free to concatenate your strings using strcat.

Resources