Array is being modified - c

I'm trying to replicate the function strcat. The problem is that my array src is being modified even though I'm just use it to copy.
#include <stdio.h>
char *ft_strcat(char *dest, char *src)
{
int i = 0;
int c = 0;
while (dest[i] != '\0')
i++;
while (src[c] != '\0')
{
dest[i] = src[c];
c++;
i++;
}
dest[i] = '\0';
return dest;
}
int main(void)
{
char src[] = "_And Good Bye";
char dest[] = "Hello World";
char *ptr;
printf("\nString 1: %s\nString 2: %s\n", src, dest);
ptr = ft_strcat(dest, src);
printf("\nAfter strcat function.\nString 1: %s\nString 2: %s\n", src, dest);
return 0;
}
Output:
String 1: _And Good Bye
String 2: Hello World
After strcat function.
String 1: And Good Bye
String 2: Hello World_And Good Bye
After I run ft_strcat(dest, src), my char src looses the character, "_". I don't understand why if I only use it to be copied.
I expect that src is not modified.

dest has exactly enough memory to store "Hello World". When you append src to it you're overwriting adjacent memory. That adjacent memory happens to contain src. There's no guarantee that it will, but stack memory is often allocated this way.
For example, if I print out the memory address of src and dest I see...
printf("src: %p\ndest: %p\n", &src, &dest);
src: 0x7ffeea74e31a
dest: 0x7ffeea74e30e
The memory looks like this.
001111111111111111
ef0123456789abcdef
Hello World0_And Good Bye0
^ ^
dest src
When you concatenate src onto dest you overwrite the adjacent memory resulting in...
001111111111111111
ef0123456789abcdef
Hello World_And Good Bye00
^ ^
dest src
You need to allocate dest to have enough space.
// "Hello World" + "_And Good Bye" + null byte
char dest[25] = "Hello World";
In a real program you'd allocate dest as dynamic memory and reallocate it to have enough space.
char *dest = malloc(12);
strcpy(dest, "Hello world");
dest = realloc(dest, strlen(dest) + strlen(src) + 1);

The actual type of a string literal in C is char [N], wherein N is the minimum amount of space required to store the characters of the string, including the null terminating byte.
In the case where you use a string literal to initialize an array of an unknown size (char foo[] = ...), the resulting array is given the same typing as the string literal.
So in,
char src[] = "_And Good Bye";
char dest[] = "Hello World";
src will have the type char [14], and dest the type char [12].
Knowing this, it becomes obvious that dest does not have enough room to append the contents of src (zero excess memory, in fact). Care must always be taken to guarantee that there is enough room, otherwise you risk Undefined Behavior.
At a minimum, you would need char dest[25], though it may be prudent to drastically oversize your destination buffer.
char dest[512] = "Hello World";
const char *src = "_And Good Bye";
Initializing dest in this way fills the rest of its memory with zeroes.

For starters the function should be declared at least like
char *ft_strcat(char *dest, const char *src);
because the source string is not changed within the function.
Within the function you are trying to append the source string to the end of the destination string but the array that contains the destination string has no enough memory to accommodate also the source string, See the declarations of the arrays
char src[] = "_And Good Bye";
char dest[] = "Hello World";
You need to enlarge the array dest.
For example you could write
char src[] = "_And Good Bye";
char dest[ 2 * sizeof( src )] = "Hello World";
Objects of the type int in general are unable to store all possible lengths of strings. For example the function strlen or the operator sizeof return values of the type size_t
In fact the declarations of the variables i and c
int i = 0;
int c = 0;
are redundant within the function.
The function can look the following way
char * ft_strcat( char *dest, const char *src )
{
char *p = dest;
while ( *p ) ++p;
while ( ( *p++ = *src++ ) != '\0' );
return dest;
}

Try to use Const modifier in source parameter. that's my first point.
char *strcat(char *destination, const char *source)

Related

How to remove a single character from the beginning of a character array? [duplicate]

I have a string:
str1 = "abcabcabc";
How can I remove the first character? I would like the end result to be:
str1 = "bcabcabc";
If you have a character pointer to a string like:
char *s = "This is my string";
then you can just do s++.
If you have a character array, your best bet may be to have a pointer to that array as well:
char s[] = "This is my string";
char *ps = s;
then you can do ps++ and make sure you use ps rather than s.
If you don't want to have a separate pointer to your array then you can use memmove to copy the data:
memmove (s, s+1, strlen (s+1) + 1); // or just strlen (s)
though none of those will work for an initially empty string so you'll have to check that first. Also keep in mind it's not advisable to attempt modifying string literals in this way (or any way, really) since it's undefined as to whether that's allowed.
Another solution is to simply code up a loop:
for (char *ps = s; *ps != '\0'; ps++)
*ps = *(ps+1);
*ps = '\0';
This will work for all strings, empty or otherwise.
Pointer tricks (zero-cost):
char* s = "abcd";
char* substr = s + 1;
// substr == "bcd"
Or:
char s[] = "abcd";
char* substr = s + 1;
// substr == "bcd"
In-place via memmove:
char s[] = "abcd";
char* substr = s + 1;
memmove(s, substr, strlen(substr) + 1);
// s == "bcd"
Notice that we must use char[] rather than char*, which would refer to read-only memory, as described here. Furthermore, one should not use strcpy in-place because the src and dest must not overlap for strcpy.
Into a new string via strcpy:
char* src = "abcd";
char* substr = src + 1;
char dest[strlen(substr) + 1];
strcpy(dest, substr);
// dest == "bcd"
Into a new string via C++'s std::string::substr:
std::string src = "abcd";
std::string dest = src.substr(1);
// dest == "bcd"
Into a new string via C++'s std::copy:
std::string src = "abcd";
std::string dest;
std::copy(src.begin() + 1, src.end(), std::back_inserter(dest));
// dest == "bcd"
There's a couple dozen other ways (particularly when including C++), but I'll stop here. :)
If you really meant to say
char str1 [] = "abcabcabc";
Then the easiest thing is
str1 = &str1[1];
If you want to modify the actual data, then you have to just move everything up one position. You can use a loop for that or memmove(). A recursive function is overkill.
If you really meant C++ and you're using the string object then you can use
str1 = str1.substr(1);
Here is one way to do it:
int index = 0; //index to cull
memmove( &word[ index ] , &word[ index +1], strlen( word ) - index) ;
Well as far as i know if you are worried about memory allocation you have to copy (str1+1) into a new string that you personally allocate memory for, then free the first pointer.
The really simple way to do it would be to just increment str1 with str1++; That would make it point one character farther than it used to and give you the desired result with just a line of code.
#include <stdio.h>
#include <conio.h>
main(){
char a[10];
int i;
gets(a);
for (i = 0; a[i] != '\0'; i++) {
a[i] = a[i + 1];
}
printf("\n");
puts(a);
getch();
}
#include <stdio.h>
int main() {
char a[15] = "!Hello world!";
sprintf(a,"%s",a+1);
printf("%s",a);
}

A strcat() implementation, how to realloc enough space to include both strings in C?

I am trying to implement the strcat function by myself, using pointers.
My pseudo-code is:
receive 2 char pointers (which means 2 strings (= 2 char arrays)).
create a copy of the dest array
realloc() space of dest to be the sum of the sizes of source string + dest string, because I need the dest string to include in the end both of the strings.
create a pointer that points to the first index of the dest string, this pointer will be returned as the function's return value.
run 2 simple while loops on both source and copy of dest strings, and while doing this, copy all contents to the dest
free all allocated pointers
return the address that points to the first index of the dest string by return the created pointer that was created for this exact purpose.
So. I wrote this:
char *StrCat(char *dest, const char *src)
{
size_t size = strlen(dest) + strlen(src) + 1;
char *temp = (char *) malloc(strlen(dest) + 1);
char *start = dest;
dest = (char *) realloc(dest, size);
strcpy(temp,dest);
while (*src)
{
*dest = *src;
src++;
dest++;
}
while (*temp)
{
*dest = *temp;
temp++;
dest++;
}
*dest = '\0';
free(temp);
return start;
}
void strcatTest()
{
char source[] = "this is source of cat";
char dest4[100] = "this is dest of cat";
StrCat(dest4,source);
puts(dest4);
}
and I'm getting:
realloc(): invalid pointer.
I know there are a lot of working and better implementations of strcat around the internet and on stackoverflow, but my purpose here is to understand what did I do wrong and why I failed to create a working implementation.
What went wrong with my understanding of starcat()?
Beware, you can only use realloc on a pointer that has previously been alloc-ed, and not on a pointer to an automatic or static storage array.
So those lines are enough to cause the error:
char *StrCat(char *dest, const char *src)
{
...
dest = (char *) realloc(dest, size);
...
char dest4[100] = "this is dest of cat";
StrCat(dest4,source);
This is the reason why the standard library does not try to reallocate...
From the C Standard (7.23.3.1 The strcat function)
2 The strcat function appends a copy of the string pointed to by s2
(including the terminating null character) to the end of the string
pointed to by s1. The initial character of s2 overwrites the null
character at the end of s1. If copying takes place between objects
that overlap, the behavior is undefined.
So within the standard C string function strcat neither allocation or reallocation memory is present. The destination character array shall be initially large enough to accommodate within itself one more string.
Take into account that you need to rename your function. Otherwise there will be a conflict between your function and the standard function.
The function definition can look the following way (without using any standard string function)
char * new_strcat( char *s1, const char *s2 )
{
char *p = s1;
while ( *p ) ++p;
while ( ( *p++ = *s2++ ) );
return s1;
}
Here is a demonstrative program.
#include <stdio.h>
char * new_strcat( char *s1, const char *s2 )
{
char *p = s1;
while ( *p ) ++p;
while ( ( *p++ = *s2++ ) );
return s1;
}
int main(void)
{
char s1[14] = "Hello ";
const char *s2 = "World!";
puts ( new_strcat( s1, s2 ) );
return 0;
}
The program output is
Hello World!
If you want to write a new function that combines two strings creating a new character array (such a function is a different function compared with the standard string function strcat) then the function can be declared and defined the following way (in this implementation there is used the standard string function strlen though it can be written without using the function).
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char * combine( const char *s1, const char *s2 )
{
char *result = malloc( strlen( s1 ) + strlen( s2 ) + 1 );
if ( result )
{
char *p = result;
while ( *s1 ) *p++ = *s1++;
while ( ( *p++ = *s2++ ) );
}
return result;
}
int main(void)
{
const char *s1 = "Hello ";
const char *s2 = "World!";
char *p = combine( s1, s2 );
if ( p ) puts( p );
free( p );
return 0;
}
Again the program output is
Hello World!
As for your function then it is incorrect and does not make any sense. For example the user can pass to the function a character array with automatic storage duration. You may not reallocate it dynamically using realloc.
Or you at first assign the pointer start with the value of the pointer dest but then the memory pointed to by the pointer dest was reallocated. As a result the pointer start has an invalid value that is returned from the function.
char *start = dest;
dest = (char *) realloc(dest, size);
//...
return start;
Also you are trying to copy strings in the reverse order relative to each other, At first you are copying the string pointed to by the pointer src and then the string that initially was pointed to by the pointer dest. S0 you are not appending the second string to the tail of the first string.
Pay attention to your function declaration
char *StrCat(char *dest, const char *src);
The first parameter without the qualifier const means that the string pointed to by the pointer dest will be changed in place. So even the function declaration contradicts your function implementation because you are not changing the destination character array in place. You are trying to create a new character array.

Function to reverse a string in C - What if is a string literal?

I have coded the following function that will reverse a String in C:
void reverse(char *str) {
int length = strlen(str) - 1;
for (int i=0; i < length/2; i++) {
char tmp = str[i];
str[i] = str[length - i];
str[length - i] = tmp;
}
}
This works if I do this:
char a[]="Hello";
reverse(a);
But if I call it passing a string literal, such as:
char *a = "Hello";
It won't work.
So, how would I modify my function so that it can accept string literals and reverse them?
You can not do that, string literals are constants in C
Perhaps, you need to copy the string, much like you do it in your first example, where you initialize a char array using a string literal.
You better of copying string to some other temp string.
Use another char* to copy original string. Allocate sufficient memory.
Copy sources string to this one. Don't forget to null terminate it.
reverse..
Dont forget to free this memory after use.
char *a1 = "Hello";
char* copy_a1 = malloc(sizeof(char)*(strlen(a1)+1));
strncpy(copy_a1, a1, strlen(a1));
copy_a1[strlen(a1)] = '\0';
reverse(copy_a1);
//free memory used.
The problem is C history.
char *a = "Hello"; should be const char *a = "Hello";. But const came in after C was successful so char *a = "Hello"; was allowed to remain OK syntax.
Had code been const char *a = "Hello";, reverse(a); would generate a warning (or error).
To modify create something like:
char *reverse(char *dest, const char *src);

Bus error in a simple C program

I am trying to reverse a C style string using the following simple program.
#include "stdio.h"
void reverse (char * str);
int main (int argc , char* argv[]){
char *str = "hello";
reverse(str);
return 0;
}
void reverse (char *str)
{
char *end = str;
char tmp;
if(str){
while(*end){
++end;
}
--end;
while(str < end){
tmp = *str;
*str++ = *end;
*end-- = tmp;
}
}
}
I can't figure out why I get a "bus error" when I try to run the above program. I am using i686-apple-darwin10-gcc-4.2.1. Thanks
If you change char *str = "hello"; to char str[] = "hello"; your error will go away, since string literals are stored in a read-only part of memory and trying to modify "hello" may cause your program to crash (as it does in this case).
Declaring str as a char[] will copy the literal "hello" into a non-const buffer that you can modify the contents of.
String literals in C are stored in the .data section of the binary which is read only memory. When saving it as const char * or char * they are non modifiable (in some cases if you modify the access fails silently or in your case you get a bus error because it's ROM).
Try using char str[] = "hello"; instead (I believe this should work, but I may be wrong).

c remove the first character of an array

I have a string:
str1 = "abcabcabc";
How can I remove the first character? I would like the end result to be:
str1 = "bcabcabc";
If you have a character pointer to a string like:
char *s = "This is my string";
then you can just do s++.
If you have a character array, your best bet may be to have a pointer to that array as well:
char s[] = "This is my string";
char *ps = s;
then you can do ps++ and make sure you use ps rather than s.
If you don't want to have a separate pointer to your array then you can use memmove to copy the data:
memmove (s, s+1, strlen (s+1) + 1); // or just strlen (s)
though none of those will work for an initially empty string so you'll have to check that first. Also keep in mind it's not advisable to attempt modifying string literals in this way (or any way, really) since it's undefined as to whether that's allowed.
Another solution is to simply code up a loop:
for (char *ps = s; *ps != '\0'; ps++)
*ps = *(ps+1);
*ps = '\0';
This will work for all strings, empty or otherwise.
Pointer tricks (zero-cost):
char* s = "abcd";
char* substr = s + 1;
// substr == "bcd"
Or:
char s[] = "abcd";
char* substr = s + 1;
// substr == "bcd"
In-place via memmove:
char s[] = "abcd";
char* substr = s + 1;
memmove(s, substr, strlen(substr) + 1);
// s == "bcd"
Notice that we must use char[] rather than char*, which would refer to read-only memory, as described here. Furthermore, one should not use strcpy in-place because the src and dest must not overlap for strcpy.
Into a new string via strcpy:
char* src = "abcd";
char* substr = src + 1;
char dest[strlen(substr) + 1];
strcpy(dest, substr);
// dest == "bcd"
Into a new string via C++'s std::string::substr:
std::string src = "abcd";
std::string dest = src.substr(1);
// dest == "bcd"
Into a new string via C++'s std::copy:
std::string src = "abcd";
std::string dest;
std::copy(src.begin() + 1, src.end(), std::back_inserter(dest));
// dest == "bcd"
There's a couple dozen other ways (particularly when including C++), but I'll stop here. :)
If you really meant to say
char str1 [] = "abcabcabc";
Then the easiest thing is
str1 = &str1[1];
If you want to modify the actual data, then you have to just move everything up one position. You can use a loop for that or memmove(). A recursive function is overkill.
If you really meant C++ and you're using the string object then you can use
str1 = str1.substr(1);
Here is one way to do it:
int index = 0; //index to cull
memmove( &word[ index ] , &word[ index +1], strlen( word ) - index) ;
Well as far as i know if you are worried about memory allocation you have to copy (str1+1) into a new string that you personally allocate memory for, then free the first pointer.
The really simple way to do it would be to just increment str1 with str1++; That would make it point one character farther than it used to and give you the desired result with just a line of code.
#include <stdio.h>
#include <conio.h>
main(){
char a[10];
int i;
gets(a);
for (i = 0; a[i] != '\0'; i++) {
a[i] = a[i + 1];
}
printf("\n");
puts(a);
getch();
}
#include <stdio.h>
int main() {
char a[15] = "!Hello world!";
sprintf(a,"%s",a+1);
printf("%s",a);
}

Resources