How to reverse string correctly? [duplicate] - c

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to reverse a string in place in c using pointers?
I was trying to reverse a string using C.
A segmentation fault occurs. Any idea why?
Here's my code:
#include <stdio.h>
#include <string.h>
int main(void)
{
char *str1 = "abbd";
char *str2;
str2 = str2 + strlen(str1)-1;
while(*str1 != '\0')
*(str2--) = *(str1++);
printf("%s", str2);
return 0;
}

Nothing's properly allocated (allocate the proper length at declaration or malloc it) and you don't really move through the strings and check for the end of your condition as fitted (try str[i]). You have awaken the kraken.

Looks like you didn't allocate any space for str2, just made the pointer.

char *str2;
str2 = str2 + strlen(str1)-1;
You declared a pointer str2, but initialize its value to garbage. (str2 + ...)
Are you trying to do an in-place modification? That won't work for this code, the char *foo="bar"; format places the "bar" in a write-protected memory space on platforms that support it.
Are you trying to do an out-of-place modification? If so, you forgot to allocate that space.

You're not allocating memory for str2.
str2 = (char *)malloc(sizeof(char) * (strlen(str1) + 1));
I haven't tried it, but it seems like you're going to want to set str2 = str2 + strlen(str1), otherwise I think you'll run off the "front" of your str2 buffer as well.
I would recommend treating your strings as arrays, and let the compiler do the pointer arithmetic for you.

Related

C String Concatenation using Function [duplicate]

This question already has answers here:
Returning an array using C
(8 answers)
Closed 3 years ago.
I just want to concatenate two strings and a separator using a function.
But in main() I am not getting the concatenated string.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* PathCreation(char* Str1, char* Str2, char* Separator=(char*)"/"){
char CreatedPath[strlen(Str1)+strlen(Str2)+strlen(Separator)+1];
strncpy(&CreatedPath[0], Str1, strlen(Str1));
strncpy(&CreatedPath[strlen(Str1)], Separator, strlen(Separator));
strncpy(&CreatedPath[strlen(Str1)+1], Str2, strlen(Str2));
CreatedPath[strlen(Str1)+strlen(Str2)+1]='\0';
//printf("\n%s", CreatedPath);
return CreatedPath;
}
int main(void)
{
char str1[] = "foo";
char str2[] = "bar";
char* ccat=PathCreation(str1, str2);
puts(str1);
puts(str2);
puts(ccat);
}
Since you've been programming in C style, I'll stick to C style. But I should point out that your code is only valid in C++ because of the default argument.
The issue is that when you simply declare something you're allocating it to the stack, stacks are destroyed once a function exits and attempting to use data after the stack has been destroyed is undefined behaviour, which means that the code may work as you expect on occasion but it may also end up pointing to garbage or simply crashing.
Instead you'll need to allocate it on the heap so that it persists after the function exits. Replace the line where you allocate your string with:
char* CreatedPath = (char*)malloc(sizeof(char)*(strlen(Str1)+strlen(Str2)+strlen(Separator)+1));

Dereference C string pointer into variable

I have the following simple program which creates a pointer to the first character of a string:
char str[] = "Hello world";
char *p = &str[0];
How can I then get this string back into a variable using only the pointer?
Dereferencing the pointer just gives the first character of the string - as somewhat expected - so I'm assuming that there is no 'simple' way to achieve this and it will instead require writing extra code.
The current way I would approach this would be as follows:
Iterate from the pointer until a null terminator is reached to find the length of the string
Create a new char array with this length
Iterate through again inserting characters into this array
Is there a library function to achieve this, or if not, a simpler way that doesn't involve iterating twice?
Yes you have to "do it by hand". Because there are no objects in C - you need to take care of all that happens in the code.
You can use malloc, strlen and memcpy:
char str[] = "Hello world";
char *p = malloc(strlen(str) + 1);
if (!p) { abort(); }
memcpy(p, str, strlen(str) + 1);
You can use strcpy and forget about one strlen:
char *p = malloc(strlen(str) + 1);
if (!p) { abort(); }
strcpy(p, str);
Or you can use strdup from POSIX or a C extension:
char *p = strdup(str);
if (!p) { abort(); }
...
Is there a library function to achieve this, or if not, a simpler way that doesn't involve iterating twice?
As said in comment, strdup() will do exactly what you want. But here there is another problem (by your point of view): strcpy() will iterate the string twice, because there is no other way to duplicate a string.
By definition, strings in C are a sequence of characters somewhere in memory, with the last one character being a NUL (with single L), the value 0 (in a char). References to strings are pointers to the first character in the sequence depicted above. Note that two different strings can point to the same memory (they are not so different then...), or a string can point into the middle of another. These two cases are somewhat particular but not uncommon. The memory for strings must be managed by the programmer, who is the only one to know where allocate and deallocate space for strings; functions like strcpy() do nothing special in this regard, they are (presumably) well written and optimized, so maybe to copy a string the behavior is not plain as I depicted it before, but the idea is the same.
try this code:
#include "stdio.h"
int main(){
char str[] = "Hello world";
int count = 12;
char (*p)[12] = &str;
printf("%c\n",(*p)[0]);
printf("%c\n",(*p)[1]);
printf("%c\n",(*p)[2]);
printf("%c\n",(*p)[3]);
printf("%s\n",(*p));
}
Here's how I would make a copy of a string using only the standard library functions:
#include <stdio.h> // printf
#include <stdlib.h> // malloc
#include <string.h> // strcpy
int main(void)
{
char str[] = "Hello world"; // your original string
char *p = (char *)malloc(strlen(str) + 1); // allocate enough space to hold the copy in p
if (!p) { // malloc returns a NULL pointer when it fails
puts("malloc failed.");
exit(-1);
}
strcpy(p, str); // now we can safely use strcpy to put a duplicate of str into p
printf("%s\n", p); // print out this duplicate to verify
return 0;
}

Segmentation fault in my strcpy

I'm writing my own strcpy due to the fact that the default one in string.h only accept a const char * as a source string to copy from.
I'm trying this very basic prototype (yes, the return isn't meaningful, I'm just trying things):
int copyStrings(char * dest, char * source){
int i=0;
while(source[i]!='\0'){
dest[i]=source[i];
i++;
}
dest[i]='\0';
return 0;
}
and it gives me SIGSEGV, Segmentation Fault error in gdb, at the line dest[i]=source[i], right at the first character. I'm pretty sure dest[i] isn't a string literal, so I should be able to modify it.
What am I doing wrong?
EDIT: here's the calling
int main(){
char * str = (char*)malloc((int)sizeof(double));
char * str2 = (char *)malloc((int)sizeof(int));
str = "hello";
str2 = "hey jude";
copyStrings(str2, str);
free(str);
free(str2);
return 0;
}
This is assigning a string literal to str2 - the very thing that you claim you aren't doing. This is actually the cause of your segfault.
str2 = "hey jude";
It also is causing a memory leak as prior to this, you malloc'd some memory and assigned it to str2 as well. But not enough memory to hold the string. Typically an int is 4 bytes and you need 9 bytes to store that string.
What you want to do is this, which allocates as many bytes as there are in the string, plus an extra one to store the \0 terminating character at the end.
str2 = malloc(strlen("hey jude")+1);
strcpy(str2,"hey jude");
or on some systems you can use POSIX function strdup() which effectively does the job of the above in one handy function call.
str2 = strdup("hey jude");
Let's go at it line by line and see where it goes wrong:
int main(){
char * str = (char*)malloc((int)sizeof(double));
char * str2 = (char *)malloc((int)sizeof(int));
str = "hello";
str2 = "hey jude";
copyStrings(str2, str);
free(str);
free(str2);
return 0;
}
int main(){ - this is an improper definition of main. Should be int main(int argc, char **argv)
char * str = (char*)malloc((int)sizeof(double)); - defines str, then allocates (probably) 8 bytes of memory and assigns its address to str. malloc takes a size_t argument, so the cast (int)sizeof(double) is incorrect. Also, in C the return value of malloc should never be cast. So this line should be char * str = malloc(sizeof(double));
char * str2 = (char *)malloc((int)sizeof(int)); - all the same problems as the preceding line. Should be char *str2 = malloc(sizeof(int));
str = "hello"; - causes a memory leak, because the memory you JUST ALLOCATED two lines earlier is now irretrievably lost. You've got two options here - either don't allocate the memory when defining str or free it first. Let's do the latter:
free(str);
str = "hello";
str2 = "hey jude"; - same problem, similar solution:
free(str2);
str2 = "hey jude";
copyStrings(str2, str); - here you're telling your routine to copy the constant string "hello" over the top of the constant string "hey jude". This will work fine on some systems, but will blow up on other systems. The question is in the treatment of the constant string "hey jude". If it's stored in modifiable memory the code will work just fine. If it's stored in memory which is marked as being unmodifiable, however, it will blow up. It seems that the latter is the case on your system. To fix this you probably want to go back to the previous line and change it to
str2 = malloc(20);
That's more memory than you'll need, but it will work just fine.
free(str); - you're attempting to free the constant string "hello", which is not dynamically allocated memory. This needed to be done prior to the assignment str = "hello";.
free(str2; - same problem as above. This needed to be done prior to the assignment str2 = "hey jude";.
} - correct
Best of luck.

How can I concatenate strings in C? [duplicate]

This question already has answers here:
Appending strings in C
(6 answers)
Closed 8 years ago.
How can I concatenate strings this way?
For example:
char *txt = "Hello";
txt=txt+"World!";
I tried it but it wasn't.
txt is a pointer and memory should be allocated to it.
It is good to have the below checks
The amount of memory which needs to allocated can be calculated by
size_t size = strlen("Hello") + strlen("World");
char *txt = malloc(size + 1);
Check the return value of malloc() before accessing it.
if(txt != NULL)
Dynamically this can be done:
char *txt = malloc(size+1); /* Number of bytes needed to store your strings */
strcpy(txt,"Hello");
strcat(txt,"World");
The allocated memory should be freed after using it like
free(txt);
Alternatively you can have
char txt[30];
strcpy(txt,"Hello");
strcat(txt,"World");
here is classic way to concat strings:
char *txt = "Hello";
char *txt2 = "World!";
char *txt3 = malloc(strlen(txt) + strlen(txt2) + 1); // don't forget about ending \0
strcpy(txt3,"Hello");
strcat(txt3,"World");
don't forget to free allocated memory
Avoid the memory leak using malloc - use arrays
i.e.
char txt[100];
strcpy(txt, "hello");
strcat(txt, "world");
This is covered in all C text books
To do it properly you have many options you could declare an array of char and use what #EdHeal suggested, but you should know in advance the length of both strings combined or you can overflow the array, and that is undefined behavior.
Or, you cold use dynamic memory allocation, but that is more complicated than just calling malloc and strcpy since you need to be very careful.
First of all, you have to know that in c strings require a '\0' character at the end of the string so when you allocate memory you should account for it.
The length of the string is obtained by means of the strlen function, which you should try to use only once per string since it computes the length, so it's expensive and it's redundant to use it more than once for the same string.
When using malloc the system may run out of memory, in that case malloc will return a special value NULL, if it did, any operation on the resulting pointer will be undefined behavior.
Finally when you no longer need the constructed string, you have to release resources to the operating system, usgin free.
This is an example of what I mean
char *text;
size_t lengthOfHello;
size_t lengthOfWorld;
lengthOfHello = strlen("Hello");
lengthOfWorld = strlen("World");
text = malloc(1 + lengthOfHello + lengthOfWorld);
if (text != NULL)
{
strcpy(text, "Hello");
strcat(text, "world");
/* ... do stuff with text ... */
free(text);
}
the terminating '\0' is already in "Hello" and it will be copied by strcpy.

recursive strcpy function [duplicate]

This question already has answers here:
Access violation when using strcpy?
(8 answers)
Closed 9 years ago.
#include <stdio.h>
char *strcpy_r(char* s, char* t);
int main()
{
char *s = {"Bob"};
char *t = {"Billy"};
char *ptr;
ptr = strcpy_r(s, t);
printf("%s\n", ptr);
return 0;
}
char* strcpy_r(char* s, char* t)
{
if((*s = *t) != '\0')
strcpy_r(s + 1, t + 1);
return s;
}
I'm just doing this for practice, but when I compiled it. I got a seg fault from main. Could someone tell me what might've caused this seg fault?
Congratulations, you have invoked undefined behavior twice within one line.
First, you can't modify the contents of a string literal. So strcpy()ing onto "foo" is wrong.
Two, even if you could: you're copying a string to a buffer that is shorter than the string. This is UB again.
You are trying to modify a constant string. This is wrong! Chances of segfault live when you modify a constant string.
Instead do this:
char s[10] = "Bob";
char t[10] = "Billy";
char *ptr;
You can't overwrite the memory that's used to hold a quoted string. That'll segfault instantly.
String literals are constant, i.e. they cant change. You're also trying to copy a longer string into a shorter string, which will write beyond the bounds of the destination string.
Both of these problems leads to undefined behavior which can cause a crash.
To solve the first problem, you have to use an array for the destination string. To solve the other problem, you have to make sure the destination array is at least as large as the source string (including its terminating '\0').

Resources