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.
Related
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
Making my own version of strtrim in C and its working fine but I wonder why it's working if I declare 2 array of char, like this:
static int is_set(const char *set, char c)
{
char *s;
s = (char *)set;
while (*s)
{
if (*s == c)
return (1);
s++;
}
return (0);
}
static char *ft_strsub(char const *str, unsigned int start, unsigned int end)
{
char *res;
char *s;
size_t size;
int i;
size = end - start;
res = malloc(size + 1);
if (!res)
return (res);
s = (char *)str + start;
i = 0;
while (*s && end-- > start)
res[i++] = *s++;
res[i] = 0;
return (res);
}
char *ft_strtrim(char const *s1, char const *set)
{
char *start;
char *s;
s = (char *)s1;
while (*s && is_set(set, *s))
s++;
if (!*s)
return (s);
start = s;
while (*s)
s++;
while (is_set(set, *--s))
;
if (*s)
*++s = 0;
return (ft_strsub(start, 0, s1 - s));
}
int main(void)
{
char tst[] = " xxxtripouille";
char tst2[] = " x";
char * s = ft_strtrim(tst, tst2);
printf("%s\n", s);
free(s);
return (0);
}
But not if I pass directly a string directly in param. I'm getting bus error if I do this
int main(void)
{
/*char tst[] = " xxxtripouille";
char tst2[] = " x";*/
char * s = ft_strtrim(" xxxtripouille", " x");
printf("%s\n", s);
free(s);
return (0);
}
I must have missed something in my training ^^Thank's in advance !
EDIT:
Thank's for reply !
Thank you for your advice, I took care to write them down, I thank you again, and I also found out why it wasn't working, it's because I'm trying to close the string and as you told me: it's a read-only string;
char *ft_strtrim(char const *s1, char const *set)
{
char *start;
char *s;
s = (char *)s1;
while (*s && is_set(set, *s))
s++;
if (!*s)
return (ft_strdup(s));
start = s;
while (*s)
s++;
while (is_set(set, *--s))
;
if (*s)
++s;
return (ft_strsub(start, 0, s - start));
}
Here's a few lines of code you might consider to replace your is_set() function:
static int matchAny( const char *set, char c ) {
const char *s = set;
for( ; *s && *s != c; s++ )
; // just searching
return *s != '\0'; // true = match found
}
Don't "cast away" const-ness unnecessarily. Exploit the "conditional" segment of the for() loop. Return is also a conditional: "If not reaching the end of the string of 'bad' characters, then 'c' was 'matched' in that string.
If you get "trimming the front" working, perhaps a simple "reverse string" can be used to "trim the back end, too", then "reverse string" once more. Re-use code that works.
Seeing this function, it can be made even simpler:
static int matchAny( const char *set, const char c ) {
while( *set && *set != c )
set++; // just searching
return *set != '\0'; // true = match found
}
Often the best solution is to use fewer resources (like variables) but to use them wisely. Then, flaws have fewer places to hide.
At least this statement does not make a sense
return (ft_strsub(start, 0, s1 - s));
because there can be passed a negative value s1 - s that will be converted to a very big positive value in the function ft_strsub because the corresponding parameter has an unsigned integer type.
Pay attention to that the compiler can issue a message that you are discarding the qualifier const as for example
char *s;
s = (char *)s1;
Also the function can return a pointer that does not point to a dynamically allocated array that you are tries to free with the function free
if (!*s)
return (s);
//...
free(s);
I am writing a method to remove whitespaces from a String passed as a pointer to a void function as follows -
char * mystrcpy(char * dest, char * str) {
dest = malloc(sizeof(str));
char * tep = dest;
while(*dest++ = *str++) {
}
return tep;
}
void trimWhiteSpace(char * str){
int counter = 0;
int i = 0;
char * res = malloc(sizeof(str));
for(i = 0; str[i]; i++) {
if(str[i] != ' ')
res[counter++] = str[i];
}
res[counter] = '\0';
mystrcpy(str, res);
printf("I got %s\n", str);
}
However, when I try to test my method using the main -
int main() {
char * myStr = (char*)malloc(sizeof(char) * 50);
myStr = "Hello World ! ";
trimWhiteSpace(myStr);
printf("%s", myStr);
return 0;
}
the program prints
"HelloWorld!"
inside of the void trimWhiteSpace(char * str) method but that is not the case with the main which prints the unmodified string.
How do I make sure that the main method prints the same string as printed by the trimWhiteSpace method?
Your program starts with a memory leak.:)
int main() {
char * myStr = (char*)malloc(sizeof(char) * 50);
myStr = "Hello World ! ";
//...
At first you allocated memory and assigned its address to pointer myStr
char * myStr = (char*)malloc(sizeof(char) * 50);
and in the next statement you reassigned the pointer with the address of a string literal
myStr = "Hello World ! ";
Take into account that string literals are immutable in C and C++. Any attempt to modify a string literal results in undefined behaviour.
You should use standard C function strcpy that to copy the string literal in the allocated memory.
strcpy( myStr, "Hello World ! " );
Or another error. You are using operator sizeof applied to a pointer
char * mystrcpy(char * dest, char * str) {
dest = malloc(sizeof(str));
^^^^^^^^^^^
Usually sizeof( char * ) is equal to 4 or 8 depending on the environment where the program was compiled.
You should use another standard C function strlen. For example
char * mystrcpy(char * dest, char * str) {
dest = malloc( strlen( str ) + 1);
There are other errors in the program.
Nevertheless the function that removes blanks could be written much simpler.
Here is a demonstrative program
#include <stdio.h>
char * trimWhiteSpace( char * str )
{
char *q = str;
char c = ' ';
while ( *q && *q != c ) ++q;
char *p = q;
while ( *q )
{
if ( *++q != c ) *p++ = *q;
}
return str;
}
int main( void )
{
char myStr[] = "Hello World ! ";
puts( myStr );
puts( trimWhiteSpace( myStr ) );
}
Its output is
Hello World !
HelloWorld!
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.
I'm working on a project meant to create functions to perform different actions, but I'm having trouble implementing one of the functions.
int main()
{
char str1[30] = "Hello";
char str2[30] = "Goodbye old friend";
char str3[30];
char *p = strCopy(str3, "Annie");
printf("(Annie) %s\n", p);
p = strString(str3, "nn");
printf("(nnie) %s\n", p);
strCopy(str3, "HeloHellooo");
p = strString(str3, "ello");
printf("(ellooo) %s\n", p);
return 0;
}
char *strCopy(char *s1, const char *s2)
{
char *b = s1;
while (*s2!='\0')
{
*s1 = *s2;
s1++;
s2++;
}
*s1 = '\0';
return b;
}
char *strString(const char *s1, const char *s2) // returns a string that starts with the characters in *s2. For example: char *strString ("Annie", "nn") should return "nnie".)
{
char *test;
char *b = test;
while (*s1 != '\0' && *s2 != '\0')
{
if (*s1 == *s2)
{
*test = *s1;
}
s1++;
s2++;
}
*test = '\0';
return b;
}
I'm having trouble figuring out how to return a value in char *strString when constant integers are the only two parameters. When I try, the program crashes. Keep in mind that the parameters, function declarations, and what's inside main() have to be exactly as they're written. It's code given to me as part of the project. I can only manipulate what goes inside of the functions. I'm also not permitted to use arrays in any of my functions.
(The code inside of *strString is obviously not final. I'm just having trouble testing anything while I can't figure out how to return a value.)
Inside strString you use the uninitialized pointer test:
char *b = test; // oops
...
*test = *s1; // oops
You could start with:
char *test = NULL;
Then you could update test when you find your substring. At no stage do you want to write *test =, because you are not modifying either of the input strings, nor are you creating a new string. You should be returning a pointer which points into s1 at the point where the substring can be found.