Trying to create a strcat in c - c

So, I'm trying to code a strcat function using pointers, just for studying purposes.
#include <stdio.h>
#include <string.h>
char *strcpyy(char *dest, char *orig){
char *tmp = dest;
while (*dest++ = *orig++);
return tmp;
}
char *strcatt(char *dest, char *orig){
strcpyy(dest + strlen(dest), orig);
return dest;
}
int main(){
char *a = "one";
char *b = "two";
printf("%s", strcatt(a,b));
}
When I run this code, the output is empty. Can anyone point out the problem?

String literals are read-only. Any attempt to write to a string literal will invoke undefined behavior, which means that your program may crash or not behave as intended.
Therefore, you should not use a pointer to a string literal as the first argument to strcat or your equivalent function. Instead, you must provide a pointer to an object which is writable and has sufficient space for the result (including the terminating null character), for example a char array of length 7. This array can be initialized using a string literal.
Therefore, I recommend that you change the line
char *a = "one";
to the following:
char a[7] = "one";
After making this change, your program should work as intended.

You declared two pointers to string literals
char *a = "one";
char *b = "two";
You may not append one string literal to another.
Instead you need to define the variable a as a character array large enough to contain the appended string literal pointed to by the pointer b.
And the both functions should be declared like
char *strcpyy(char *dest, const char *orig);
char *strcatt(char *dest, const char *orig);
Also as you are using standard C string functions like strlen
strcpyy(dest + strlen(dest), orig);
then it will be logically consistent to use standard C function strcpy instead of your own function strcpyy.
Otherwise without using standard string functions your function strcatt can look the following way
char * strcatt( char *s1, const char *s2 )
{
char *p = s1;
while ( *p ) ++p;
while ( ( *p++ = *s2++ ) != '\0' );
return s1;
}
Here is a demonstration program.
#include <stdio.h>
char * strcatt( char *s1, const char *s2 )
{
char *p = s1;
while ( *p ) ++p;
while ( ( *p++ = *s2++ ) != '\0' );
return s1;
}
int main( void )
{
char a[7] = "one";
const char *b = "two";
puts( strcatt( a, b ) );
}
The program output is
onetwo

You cannot modify "string literals". Those are not mutable.
The usual idiom for this sort of operation is to build up a string in a temporary working buffer that should be pre-dimensioned large enough to hold all that is required.
The following also shows more obvious code in both your functions.
#include <stdio.h>
char *strcpyy( char *dst, const char *org ) {
for( char *p = dst; (*p++ = *org++) != '\0'; /**/ )
; // loop
return dst;
}
char *strcatt( char *dst, const char *org ) {
char *p = dst;
while( *p != '\0' )
p++; //loop
while( (*p = *org++) != '\0' )
p++; // loop
return dst;
}
int main(){
const char *a = "one ";
const char *b = "two ";
const char *c = "three";
char wrk[ 64 ]; // sufficient mutable space defined
printf( "%s\n", strcatt( strcatt( strcpyy( wrk, a ), b ), c ) );
return 0;
}
one two three

Related

passing string with pointer through function c

i,m trying to write this code, it should counting the number of substring, which are not including in the string, for examples(below), in the main i was trying with pointer to work with String without using arrays but it didnt work at all!!
// count_target_string("abc of", "of") -> 1
// count_target_string("abcof", "of") -> 0
// count_target_string("abc of abc of", "of") -> 2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int countTargetString(char* text , char* string){
char d[]=" ";
char * portion = strtok(text,d);
int result=0;
while (portion!=NULL){
if (strcmp(portion,string)==0){
result++;
}
portion = strtok(NULL,d);
}
return result;
}
int main(){
printf("%d\n",countTargetString("abc of abc of","of"));
char *test ="abc of abc of";
char *d = "of";
printf("%d\n",countTargetString(test,d));
return 0;
}
strtok modifies the string.
char *test ="abc of abc of"; defines the pointer to the string literal. Modification of the string literal invokes Undefined Behaviour (UB). It is why your code does "not work at all" Same if you pass string literal reference directly to the function (ie use a string literal as a parameter) countTargetString("abc of abc of","of"));.
Your pointer must reference a modifiable string:
int main()
{
char mystring[] = "abc of abc of";
char *test = mystring;
char *d = "of";
printf("%d\n",countTargetString(test,d));
}
In the both calls of the function countTargetString
printf("%d\n",countTargetString("abc of abc of","of"));
char *test ="abc of abc of";
char *d = "of";
printf("%d\n",countTargetString(test,d));
you are passing pointers to string literals.
Though in C opposite to C++ string literals have types of non-constant character arrays nevertheless you may not change a string literal. Any attempt to change a string literal results in undefined behavior.
From the C Standard (6.4.5 String literals)
7 It is unspecified whether these arrays are distinct provided their
elements have the appropriate values. If the program attempts to
modify such an array, the behavior is undefined.
And the function strtok changes the source string inserting terminating zero characters '\0' to extract substrings.
It is always better even in C to declare pointers to string literals with the qualifier const.
Instead of the function strtok you can use function strstr.
Here is a demonstration program.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
size_t countTargetString( const char *s1, const char *s2 )
{
size_t count = 0;
size_t n = strlen( s2 );
for ( const char *p = s1; ( p = strstr( p, s2 ) ) != NULL; p += n )
{
if ( ( p == s1 || isblank( ( unsigned char )p[-1] ) ) &&
( p[n] == '\0' || isblank( ( unsigned char )p[n] ) ) )
{
++count;
}
}
return count;
}
int main( void )
{
printf("%zu\n",countTargetString("abc of abc of","of"));
const char *test ="abc of abc of";
const char *d = "of";
printf("%zu\n",countTargetString(test,d));
}
The program output is
2
2
As you can see the function parameters are also declared with the qualifier const because the function does not change passed strings.
Pay attention to that in any case to count occurrences of substrings in a string it is a bad idea to change the original string.
While strtok will not work with a string literal, strspn and strcspn can be used.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int countTargetString(char* text , char* string){
char d[]=" ";
int result = 0;
size_t span = 0;
while ( *text) {
text += strspn ( text, d);
span = strcspn ( text, d);
if ( strncmp ( text, string, span)) {
++result;
}
text += span;
}
return result;
}
int main( void) {
printf("%d\n",countTargetString("abc of abc of","of"));
char *test ="abc of abc of";
char *d = "of";
printf("%d\n",countTargetString(test,d));
return 0;
}
int count_substr(const char* target, const char* searched) {
int found = 0;
unsigned long s_len = strlen(searched);
for (int i = 0; target[i]; i++) {
// use memcmp to NOT compare the null terminator of searched
if (memcmp(target + i, searched, s_len) == 0) {
found++;
i += s_len - 1;
}
}
return found;
}
This is a very basic implementation of substring counting. For the fastest solution possible, copy the boyer moore pattern matching algorithm from wikipedia or wherever you want and modify it to cound instead of terminationg on a match.

Concat two strings through pointers not working

I made a function that concat string t to the end of string s, for my exercise I have to use pointers for this, so I did this way but its not working:
#include <stdio.h>
void strcat(char *s, char *t)
{
while (*s++);
for (*s = *t; *s = *t; s++, t++);
}
int main()
{
char c[100] = "hello";
char *w = " world\n";
strcat(c, w);
printf(c);
return 0;
}
The output of c always return "hello" instead of "hello world\n"
This while loop within the function
while (*s++);
is incorrect. After the while loop the pointer s points to after the terminating zero character '\0' due to the postfix increment operator.
The function can be declared and defined the following way
char * strcat(char *s, const char *t)
{
char *p = s;
while( *p ) ++p;
while ( ( *p++ = *t++ ) != '\0' );
return s;
}
Also you should rename the function because there is already standard string function strcat in C.
Here is a demonstration program.
#include <stdio.h>
char *string_cat( char *s, const char *t )
{
char *p = s;
while (*p) ++p;
while (( *p++ = *t++ ) != '\0');
return s;
}
int main( void )
{
char c[100] = "hello";
const char *w = " world";
puts( string_cat( c, w ) );
}
The program output is
hello world
In addition to #Vlad from Moscow good answer:
Local void strcat(char *s, char *t) assumes the strings referenced by s, t do not overlap in memory. Consider the infinite loop below if s == t.
char *p = s;
while (*p) p++;
while ((*p++ = *t++ ) != 0);
The standard C library has char *strcat(char * restrict s1, const char * restrict s2);. The restrict assumes that no-overlap and emits maybe better code> Otherwise the result in undefined behavior (UB). OP's code should also use restrict.
But what is we wanted to do strcat() and cope with overlap?
// Allow strings refenced by s,t to overlap.
char *my_strcat(char *s1, const char *s2) {
size_t s1len = strlen(s1);
size_t s2siz = strlen(s2) + 1u;
memmove(s1 + s1len, s2, s2siz);
return s1;
}
int main(void) {
char c[100] = "hello";
const char *w = c; //" world";
puts(my_strcat(c, w));
}
Output
hellohello
To handle overlap, extra work occurred to determine the size of s2.

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.

Allocating memory for string pointers? [duplicate]

This question already has an answer here:
Why can I not modify a string literal in c?
(1 answer)
Closed 2 years ago.
I'm kind of struggling with some of the basics for C. I tried to compile this program and it came up with a Signal 11 Error. I know this is to do with memory allocation, but I'm not sure how to use malloc() correctly to make this work. Can someone help?
{
char *string = "Lol";
convert_lower(string);
printf("%s\n", string);
return 0;
}
char *convert_lower(char *word) {
for ( ; *word; ++word) *word = tolower((char)*word); // J.F. Sebastian
return word;
}
You are giving convert_lower() a pointer to a string literal, so it will try to modify read-only memory. That is why you get the runtime error.
You need to make a writable copy of the string literal's data before you can then modify it, eg:
char *literal = "Lol";
char *string = malloc(strlen(literal)+1);
strcpy(string, literal);
convert_lower(string);
printf("%s\n", string);
free(string);
Which can be simplified using strdup() instead, which will handle the allocation and copy for you:
char *string = strdup("Lol");
convert_lower(string);
printf("%s\n", string);
free(string);
And then, you can simplify this further by just not allocating any dynamic memory at all:
char string[] = "Lol";
convert_lower(string);
printf("%s\n", string);
There are at least two serious errors.
The first one is that you may not change a string literal. Any attempt to change a string literal results in undefined behavior.
char *string = "Lol";
convert_lower(string);
The second one is that within the function the passed pointer is changed. so the function returns a pointer that points to the terminating zero instead of pointing to the beginning of the string.
And instead of casting to char
tolower((char)*word)
you need to cast to unsigned char
tolower( (unsigned char)*word)
The function can be defined like
char * convert_lower( char *word )
{
for ( char *p = word; *p; ++p )
{
*p = tolower( ( unsigned char )*p );
}
return word;
}
and called like
char string[] = "Lol";
puts( convert_lower(string) );
If you want to make a copy of the original string converting all characters to the lower case then the function can look the following way
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
//...
char * convert_lower( const char *word )
{
char *result = malloc( strlen( word ) + 1 );
if ( result != NULL )
{
char *p = result;
while ( ( *p++ = tolower( ( unsigned char )*word++ ) ) != '\0' );
}
return result;
}
And the function can be called like
char *string = "Lol";
char *lower_case_string = convert_lower( string );
if ( lower_case_string != NULL ) puts( lower_case_string );
free( lower_case_string );

C: copy a char *pointer to another

i have some trouble with a simple copy function:
void string_copy(char *from, char *to) {
while ((*to++ = *from++) != '\0')
;
}
It takes two pointers to strings as parameters, it looks ok but when i try it i have this error:
Segmentation fault: 11
This is the complete code:
#include <stdio.h>
void string_copy(char *from, char *to);
int main() {
char *from = "Hallo world!";
char *to;
string_copy(from,to);
return 0;
}
Thank you all
Your problem is with the destination of your copy: it's a char* that has not been initialized. When you try copying a C string into it, you get undefined behavior.
You need to initialize the pointer
char *to = malloc(100);
or make it an array of characters instead:
char to[100];
If you decide to go with malloc, you need to call free(to) once you are done with the copied string.
You need to allocate memory for to. Something like:
char *to = malloc(strlen(from) + 1);
Don't forget to free the allocated memory with a free(to) call when it is no longer needed.
In this program
#include <stdio.h>
void string_copy(char *from, char *to);
int main() {
char *from = "Hallo world!";
char *to;
string_copy(from,to);
return 0;
}
pointer to has indeterminate value. As result the program has undefined behavior.
Also function string_copy has a wrong interface. It says that it does not guarantees that string pointed to by from will not be changed.
Also there is a common convention in C that functions that deal with strings usually return pointer to the destination string.
The function should be declared like
char * string_copy( const char *from, char *to );
^^^^^^ ^^^^^
Its definition could look like
char * string_copy( const char *from, char *to )
{
for ( char *p = to; ( *p = *from ) != '\0'; ++p, ++from )
{
;
}
return to;
}
And the program could look like
#include <stdio.h>
#include <string.h>
#include >stdlib.h>
char * string_copy( const char *from, char *to );
int main( void )
{
char *from = "Hallo world!";
char *to;
to = malloc( strlen( from ) + 1 );
puts( string_copy( from, to ) );
free( to );
return 0;
}
char * string_copy( const char *from, char *to )
{
for ( char *p = to; ( *p = *from ) != '\0'; ++p, ++from )
{
;
}
return to;
}
Take into account that you may not use pointer to declared like
char *from = "Hallo world!";
char *to = "Hello everybody!";
in the function because string literals are immutable.

Resources