I have a function in 'C' that is supposed to implement my own strcpy program. Here's what I wrote. However, I am not able to debug the cause of Segmentation Fault.
#include <stdio.h>
#include <stdlib.h>
char * mystrcpy(char *dest, char *src) {
char * ptr = dest;
while (*src != '\0'){
*ptr = *src;
ptr++; src++;
//printf("Dest is \"%s\" and Source is \"%s\"\n",dest,src);
}
*ptr = '\0';
return dest;
}
int main() {
char str[] = "I rock always";
char * dest = NULL;
dest = mystrcpy(dest, str);
printf("Source String %s and Destination String %s\n", str, dest);
}
Can someone explain this behavior to me ?
You have to allocate memory for the destination string:
int main() {
char str[] = "I rock always";
char * dest = (char*)malloc(strlen(str) + 1);
dest = mystrcpy(dest, str);
printf("Source String %s and Destination String %s\n", str, dest);
}
Of course, it is good manners to free the memory eventually:
free(dest);
You never allocate any memory for *dest to point to.
It starts pointing to NULL, and then you attempt: *ptr = *src.
#include <stdio.h>
/* this the K&R version of strcpy */
char * mystrcpy(char *dest, char *src) {
char *ptr = dest;
while ( *ptr++ = *src++ ) {;}
return dest;
}
int main(void) {
char str[] = "I rock always";
char dest[sizeof str];
char *result;
result = mystrcpy(dest, str);
printf("Source String %s and Destination String %s and result %s\n", str, dest, result);
return 0;
}
Allocate memory and try....
#include <stdio.h>
#include <stdlib.h>
char * mystrcpy(char *dest, char *src)
{
char * ptr = dest;
int index=0;
while (*src != '\0')
{
*(ptr+index) = *(src+index);
index++;
}
*(ptr+index) = '\0';
return dest;
}
int main()
{
char str[] = "I rock always";
char * dest = (char*)malloc((strlen(str)+1)*sizeof(char));
dest = mystrcpy(dest, str);
printf("Source String %s and Destination String %s\n", str, dest);
free(dest);
return 0;
}
You must allocate memory for the destination string buffer.
Memory management is a very big part of C ... you need to be very careful that you allocate AND deallocate memory as it is used and becomes surplus to requirements. Failure to do so will result in segmentation faults (failing to allocate memory) and memory leaks (failing to free memory)
Other answers here give you examples of malloc so I won't repeat them here.
You should use the functions already available to you as much as possible, rather than writing your own. This avoids errors in implementation as somebody has already debugged and optimized it for you.
http://www.cs.cf.ac.uk/Dave/C/node19.html
Related
#include<stdio.h>
void my_strconcat(char*, char*);
int main()
{
char s1[] = "HelloGoodMorningEveryone1";
char s6[] = "How";
printf("String Concatenate Start! \n");
my_strconcat(s1, s6);
printf("s1:%s s6:%s \n", s1, s6);
return 0;
}
void my_strconcat(char *src, char *dest)
{
while(*dest)
dest++;
while(*src) {
*dest++ = *src++;
}
*dest = '\0';
}
output:
String Concatenate Start!
s1:elloGoodMorningEveryone1 s6:HowHelloGoodMorningEveryone1
Your destination buffer does not have any space left for storing the concatenated result. So, inside the function, you're essentially overrunning the allocated memory, creating undefined behavior.
You need to allocate enough space to the destination buffer, like
char s6[128] = "How";
so that it's able to store the concatenated result, before you try to store the result.
According to this:
strcpy vs strdup,
strcpy could be implemented with a loop, they used this while(*ptr2++ = *ptr1++). I have tried to do similar:
#include <stdio.h>
#include <stdlib.h>
int main(){
char *des = malloc(10);
for(char *src="abcdef\0";(*des++ = *src++););
printf("%s\n",des);
}
But that prints nothing, and no error. What went wrong?
Thanks a lot for answers, I have played a bit, and decided how best to design the loop to see how the copying is proceeding byte by byte. This seems the best:
#include <stdio.h>
#include <stdlib.h>
int main(){
char *des = malloc(7);
for(char *src="abcdef", *p=des; (*p++=*src++); printf("%s\n",des));
}
In this loop
for(char *src="abcdef\0";(*des++ = *src++););
the destination pointer des is being changed. So after the loop it does not point to the beginning of the copied string.
Pay attention to that the explicit terminating zero character '\0' is redundant in the string literal.
The loop can look the following way
for ( char *src = "abcdef", *p = des; (*p++ = *src++););
And then after the loop
puts( des );
and
free( des );
You could write a separate function similar to strcpy the following way
char * my_strcpy( char *des, const char *src )
{
for ( char *p = des; ( *p++ = *src++ ); );
return des;
}
And call it like
puts( my_strcpy( des, "abcdef" ) )'
free( des );
You are incrementing des so naturally at the end of the cycle it will be pointing past the end of the string, printing it amounts to undefined behavior, you have to bring it back to the beginning of des.
#include <stdio.h>
#include <stdlib.h>
int main(){
int count = 0;
char *des = malloc(10);
if(des == NULL){
return EXIT_FAILURE; //or otherwise handle the error
}
// '\0' is already added by the compiler so you don't need to do it yourself
for(char *src="abcdef";(*des++ = *src++);){
count++; //count the number of increments
}
des -= count + 1; //bring it back to the beginning
printf("%s\n",des);
free(dest); //to free the allocated memory when you're done with it
return EXIT_SUCCESS;
}
Or make a pointer to the beginning of des and print that instead.
#include <stdio.h>
#include <stdlib.h>
int main(){
char *des = malloc(10);
if(des == NULL){
return EXIT_FAILURE; //or otherwise handle the error
}
char *ptr = des;
for(char *src="abcdef";(*des++ = *src++);){} //using {} instead of ;, it's clearer
printf("%s\n",ptr);
free(ptr) // or free(dest); to free the allocated memory when you're done with it
return EXIT_SUCCESS;
}
printf("%s\n",des); is undefined behavior (UB) as it attempts to print starting beyond the end of the string written to allocated memory.
Copy the string
Save the original pointer, check it and free when done.
const char *src = "abcdef\0"; // string literal here has 2 ending `\0`,
char *dest = malloc(strlen(src) + 1); // 7
char *d = dest;
while (*d++ = *src++);
printf("%s\n", dest);
free(dest);
Copy the string literal
const char src[] = "abcdef\0"; // string literal here has 2 ending `\0`,
char *dest = malloc(sizeof src); // 8
for (size_t i = 0; i<sizeof src; i++) {
dest[i] = src[i];
}
printf("%s\n", dest);
free(dest);
You just need to remember the original allocated pointer.
Do not program in main. Use functions.
#include <stdio.h>
#include <stdlib.h>
size_t strSpaceNeedeed(const char *str)
{
const char *wrk = str;
while(*wrk++);
return wrk - str;
}
char *mystrdup(const char *str)
{
char *wrk;
char *dest = malloc(strSpaceNeedeed(str));
if(dest)
{
for(wrk = dest; *wrk++ = *str++;);
}
return dest;
}
int main(){
printf("%s\n", mystrdup("asdfgfd"));
}
or even better
size_t strSpaceNeedeed(const char *str)
{
const char *wrk = str;
while(*wrk++);
return wrk - str;
}
char *mystrcpy(char *dest, const char *src)
{
char *wrk = dest;
while((*wrk++ = *src++)) ;
return dest;
}
char *mystrdup(const char *str)
{
char *wrk;
char *dest = malloc(strSpaceNeedeed(str));
if(dest)
{
mystrcpy(dest, str);
}
return dest;
}
int main(){
printf("%s\n", mystrdup("asdfgfd"));
}
You allocate the destination buffer des and correctly copy the source string into place. But since you are incrementing des for each character you copy, you have moved des from the start of the string to the end. When you go to print the result, you are printing the last byte which is the nil termination, which is empty.
Instead, you need to keep a pointer to the start of the string, as well as having a pointer to each character you copy.
The smallest change from your original source is:
#include <stdio.h>
#include <stdlib.h>
int main(){
char *des = malloc(10);
char *p = des;
for(char *src="abcdef";(*p++ = *src++););
printf("%s\n",des);
}
So p is the pointer to the next destination character, and moves along the string. But the final string that you print is des, from the start of the allocation.
Of course, you should also allocate strlen(src)+1 worth of bytes for des. And it is not necessary to null-terminate a string literal, since that will be done for you by the compiler.
But that prints nothing, and no error. What went wrong?
des does not point to the start of the string anymore after doing (*des++ = *src++). In fact, des is pointing to one element past the NUL character, which terminates the string, thereafter.
Thus, if you want to print the string by using printf("%s\n",des) it invokes undefined behavior.
You need to store the address value of the "start" pointer (pointing at the first char object of the allocated memory chunk) into a temporary "holder" pointer. There are various ways possible.
#include <stdio.h>
#include <stdlib.h>
int main (void) {
char *des = malloc(sizeof(char) * 10);
if (!des)
{
fputs("Error at allocation!", stderr);
return 1;
}
char *tmp = des;
for (const char *src = "abcdef"; (*des++ = *src++) ; );
des = temp;
printf("%s\n",des);
free(des);
}
Alternatives:
#include <stdio.h>
#include <stdlib.h>
int main (void) {
char *des = malloc(sizeof(char) * 10);
if (!des)
{
fputs("Error at allocation!", stderr);
return 1;
}
char *tmp = des;
for (const char *src = "abcdef"; (*des++ = *src++) ; );
printf("%s\n", tmp);
free(tmp);
}
or
#include <stdio.h>
#include <stdlib.h>
int main (void) {
char *des = malloc(sizeof(char) * 10);
if (!des)
{
fputs("Error at allocation!", stderr);
return 1;
}
char *tmp = des;
for (const char *src = "abcdef"; (*tmp++ = *src++) ; );
printf("%s\n", des);
free(des);
}
Side notes:
"abcdef\0" - The explicit \0 is not needed. It is appended automatically during translation. Use "abcdef".
Always check the return of memory-management function if the allocation succeeded by checking the returned for a null pointer.
Qualify pointers to string literal by const to avoid unintentional write attempts.
Use sizeof(char) * 10 instead of plain 10 in the call the malloc. This ensures the write size if the type changes.
int main (void) instead of int main (void). The first one is standard-compliant, the second not.
Always free() dynamically allocated memory, since you no longer need the allocated memory. In the example above it would be redundant, but if your program becomes larger and the example is part-focused you should free() the unneeded memory immediately.
I have to code a function that reproduces the behavior of strcpy in c https://www.tutorialspoint.com/c_standard_library/c_function_strcpy.htm
If I understand correctly this function, it copies a string of characters from a source memory location to a destination memory location and returns the pointer to the destination memory location.
Here the code that I have produced :
#include <stdio.h>
char *ft_strcpy(char *dest, char *src)
{
char *mem = dest;
while (*src != '\0')
{
*dest = *src;
src++;
dest++;
}
*dest = '\0';
return mem;
}
int main()
{
char word[5] = "word";
printf("%s \n", word);
printf("word address is %p \n", word);
char *dest;
printf("dest address is %p", dest);
ft_strcpy(dest, word);
while (*dest != '\0'){
printf("%c", *dest);
dest++;
}
}
To test my code I declared an array of characters word containing "word" and a pointer *dest.
However when I run my code I get a 59873 segmentation fault. I figured that it is this line responsible for the error :
*dest = *src;
However I dont understand what's wrong with this line. For me, this line means "copy the value that src pointer is pointing to into the memory location that dest is pointing to".
Could someone please explain what is going wrong with this code
You never give dest a value, so it's value is undefined. Therefore your program has undefined behavior. More specifically: char* dest; just gives you a "pointer to a character" but doesn't actually set the value.
char c = 'A';
char *dest = &c;
Is 100% valid code (not for your use of dest though). What you need is to point dest at a big enough chunk of memory for your purposes. You can use dynamic memory allocation:
dest = malloc(32); // 32 is a randomly selected value
// don't forget a NULL check and to free() once done.
But if you want to avoid that can of worms for now then using a static buffer will work.
char block[10]; // 10 is randomly selected to work in your example
char *dest = block;
or
char dest[10] = { 0 }; // initializes all to 0
// but now you can't do "dest++" etc.
Like:
int main()
{
char word[5] = "word";
char block[10]; // 10 is randomly selected to work in your example
char *dest = block;
printf("%s \n", word);
printf("word address is %p \n", word);
printf("dest address is %p", dest)
ft_strcpy(dest, word);
...
char *dest;
printf("dest address is %p", dest);
ft_strcpy(dest, word);
Your first issue is you're sending dest into ft_strcpy and printf without assigning it any value. The actual value it has is indeterminate and could well be anything.
dest needs to be a pointer to memory big enough to hold word.
char *dest = malloc(strlen(word) + 1)
If we allocate the length of word + 1 byte for the null terminator, ft_strcpy will work correctly.
Then you just need to remember to use free
free(dest);
That's it.
Your only problem was ft_strcpy was acting undefined by dereferencing *dest when dest was not a valid pointer.
1 . Your *dest is dangling pointer in main so first you need to store some valid address into it by using malloc() or other method .
2 . Storing address of string from code section in array is bad programming practice .
3 . Check the modified code .
#include <stdio.h>
#include <string.h> /* for strcpy */
#include <stdlib.h> /* for malloc */
char *ft_strcpy(char *dest, char *src)
{
char *mem = dest;
while (*src != '\0')
{
*dest = *src;
src++;
dest++;
}
*dest = '\0';
return mem;
}
int main()
{
char word[5]; strcpy(word,"word");
printf("%s \n", word);
printf("word address is %p \n", word);
char *dest=malloc(strlen(word)+1); //+1 for null terminating character .
printf("dest address is %p", dest);
char *temp=dest;
ft_strcpy(dest, word);
while (*dest != '\0'){
printf("%c", *dest);
dest++;
}
free(temp);
}
I want to do in C, what can be achieved in Java as follows
String str = "hello";
System.out.println(str + 'a');
I have written the following.
1. It doesn't work
2. Is there an easier way to do this in C, something that can be achieved in java in a single line.
#include <stdio.h>
char* charcat(char str[], char c);
int main(void)
{
char str[] = "hello";
printf("%s\n",charcat(str,'a'));
}
char* charcat(char str[], char c)
{
char newstr[] = {c,'\0'};
char temp[20];
strcpy(temp,str);
strcat(temp,newstr);
return temp;
}
EDIT :
I have edited based on ameyCU's response.
char* charcat(char str[], char c);
int main(void)
{
char str[] = "hello";
printf("%s\n",charcat(str,'a'));
}
char* charcat(char str[], char c)
{
char* temp;
char newstr[] = {c,'\0'};
temp = malloc((strlen(str) + 1)* sizeof(char));
strcpy(temp,str);
return strcat(temp,newstr);
}
EDIT 2:
char* charcat(char str[], char c);
int main(void)
{
char str[] = "hello";
char temp[20];
strcpy(temp,str);
printf("%s\n",charcat(temp,'a'));
}
char* charcat(char str[], char c)
{
char newstr[] = {c,'\0'};
return strcat(str,newstr);
}
I think what you were trying to do was this:
char* charcat(char str[], char c)
{
char newstr[] = {c,'\0'};
char *temp=(char *)malloc((strlen(str)+1+1)*sizeof(char));
strcpy(temp,str);
strcat(temp,newstr);
return temp;
}
make sure you free() the pointer.
You can use strcat() function
char str1[20]="hello";
strcat(str1,"c");
printf("%s",str1);
Problem is that you return a local variable.
return temp;
temp is local variable and its scope is just inside the function it is declared.
After concatenation -strcat(temp,newstr);
You can do this -
strcpy(str,temp);
return str;
But this will also change the contents of original array.
EDIT
To keep original array intact assign a pointer to string in function and return the pointer .
And also to use functions like strcpy and strcat you need to include string.h header.
This uses snprintf() to get the required length for the target string. Memory is allocated and then snprintf() creates the target string.
#include<stdio.h>
#include<stdlib.h>
char* charcat(char str[], char c);
int main ( ) {
char str[] = "hello";
char *output = NULL;
printf ( "str-> %s\n\n", str);
if ( ( output = charcat ( str, 'a'))) {//successful return of pointer
printf ( "output-> %s\n", output);
free ( output);//release memory
}
return 0;
}
char* charcat(char str[], char c)
{
char *temp = NULL;
int length = 0;
length = snprintf ( NULL, 0, "%s%c", str, c);//get required length
if ( ( temp = malloc ( length + 1))) {//allocate plus one for '\0'
snprintf ( temp, length + 1, "%s%c", str, c);//malloc succeeds make target
}
return temp;
}
It is always better to use strncat() instead of strcat to avoid buffer overflows.
#include <cstdio>
#include <cstring>
int main ()
{
char str[20] = "hello";
strncat (str, "a", sizeof(str) - strlen(str) - 1);
printf("%s",str);
return 0;
}
Output:
helloa
RUN SUCCESSFUL (total time: 49ms)
Something like Java in a single line
// String str = "hello";
// System.out.println(str + 'a');
const char *str = "hello";
printf("%s%c\n", str, 'a');
Or is one wants to print a concatenated string, we need to do memory management.
char *charcatconst char *src, int ch) {
size_t len = strlen(src);
char *s = memcpy(malloc(len+2), src, len); // Out-of-memory check omitted.
s[len] = ch;
s[len+1] = '\0';
return s;
}
// simple usage, but a memory leak
puts(charcat("hello", 'a'));
// Better to free memory explicitly
char *s = charcat("hello", 'a');
puts(s);
free(s);
I implement a simple strcpy, but when i run it , it always give a segmentation fault.
Please help!
Below is my code:
#include <stdio.h>
char* mystrcpy(char *dst, char *src){
char *ptr = dst;
while (*src !='\0') {
*dst = *src;
dst++;
src++;
}
return ptr;
}
int main (int argc, char **argv) {
char *str1 = "abc";
char *str2 = "def";
char *str3 = NULL;
str3 = mystrcpy(str2, str1);
printf("str2 now is %s", str2);
printf("str3 is %s", str3);
return 0;
}
These are read-only. Writing to them results in undefined behavior.
char *str1="abc"; /* Read-only. */
char *str2="def";
while (*src !='\0') {
*dst = *src; /* Writes into read-only memory. */
See this C FAQ:
String constants are in fact constant. The compiler may place them in
nonwritable storage, and it is therefore not safe to modify them.
And another explanation. You should try
char str1[]="abc";
char str2[]="def";
while( *src !='\0'){
*dst=*src;
You need to dereference your pointers here, using &, not *
EDIT:
Looks like I'm having my own personal cranial segmentation fault, here - too early in the morning!
cnicutar's explanation (assigning a pointer to a string constant with char *str2 = "def";, and then trying to write to that location) is much more plausible...