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!
Related
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.
#include <stdio.h>
#include <stdlib.h>
char concaten(const char *str1,const char *str2);
int main()
{
printf("%s",concaten("Code","blocks"));
return 0;
}
char concaten(const char *str1,const char *str2) {
int i=0,j=0;
char *result;
while(*str1){
result[i++]=str1[i++];
}
while(*str2){
result[i+j++]=str2[j++];
}
return result;
}
I wrote this function to get two strings and add them to another third string; I don't understand where I am going wrong, as it doesn't print anything.
There are a number of problems with your concaten function.
First, it should be returning a char* pointer, not a char; thus, the declaration should look like this:
char* concaten(const char* str1, const char* str2);
Next, the function will need to allocate memory in which to store the concatenated strings; this can be done with the malloc() function, and the number of characters required will be the sum of the lengths of the two input strings plus one, for the required nul-terminator.
Third, the logic of your two loops is wrong. You are incrementing i and j twice per loop but not incrementing either of the source pointers.
Finally, you must add a nul-terminator at the end of your new string.
Here's a version with the above fixes applied:
char* concaten(const char* str1, const char* str2)
{
int i = 0, j = 0;
char* result = malloc(strlen(str1) + strlen(str2) + 1); // allow space for nul-terminator
while (*str1) {
result[i++] = *str1++; // Only increment i once and "str1" once
}
while (*str2) {
result[i + j++] = *str2++; // Only increment j once and "str2" once
}
result[i + j] = '\0'; // Add required nul-terminator
return result;
}
Also, as you have allocated memory (with the malloc call), you should release that when you're done with the data, using a call to free. Here's how your main might work:
int main(void)
{
char* answer = concaten("Code", "blocks");
printf("%s", answer);
free(answer);
return 0;
}
Note: You can also remove the j variable entirely, and just re-use the result[i++] expression in the second loop. I've left it in so that you can more easily relate my code to your own.
Your function has the return type char
char concaten(const char *str1,const char *str2);
but within the function you are returning the variable result
return result;
declared like a pointer of the type char *
char *result;
So the compiler will issue a message that you are trying to convert a pointer to an integer.
The function must be declared like
char * concaten(const char *str1,const char *str2);
The pointer result is not initialized and has an indeterminate value. You need to allocate memory where you will write concatenated strings.
The while loops in the function will be infinite if str1 and/or str2 are not empty strings due to conditions
while(*str1){
and
while(*str2){
These statements
result[i++]=str1[i++];
and
result[i+j++]=str2[j++];
invoke undefined behavior not only because the pointer result is not initialized but also because there is no sequence point between left and write operands where there is used the postfix increment operator ++.
Also the result string must be zero terminated.
If you are not allowed to use standard C string functions then your function can be implemented for example the following way
char * concatenate( const char *str1, const char *str2 )
{
size_t n1 = 0;
size_t n2 = 0;
while ( str1[n1] ) ++n1;
while ( str2[n2] ) ++n2;
char *result = malloc( n1 + n2 + 1 );
if ( result != NULL )
{
char *p = result;
while ( *str1 ) *p++ = *str1++;
do
{
*p++ = *str2;
} while ( *str2++ );
}
return result;
}
Also you should not forget to free the allocated memory when the result string is not needed any more.
Here is a demonstrative program.
#include <stdio.h>
#include <stdlib.h>
char * concatenate( const char *str1, const char *str2 )
{
size_t n1 = 0;
size_t n2 = 0;
while ( str1[n1] ) ++n1;
while ( str2[n2] ) ++n2;
char *result = malloc( n1 + n2 + 1 );
if ( result != NULL )
{
char *p = result;
while ( *str1 ) *p++ = *str1++;
do
{
*p++ = *str2;
} while ( *str2++ );
}
return result;
}
int main(void)
{
char *result = concatenate( "Code ", "blocks" );
if ( result != NULL ) puts( result );
free( result );
return 0;
}
The program output is
Code blocks
If you may use standard C string functions then the function concatenate can look as it is shown in the demonstrative program below.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * concatenate( const char *str1, const char *str2 )
{
size_t n1 = strlen( str1 );
size_t n2 = strlen( str2 );
char *result = malloc( n1 + n2 + 1 );
if ( result != NULL )
{
memcpy( result, str1, n1 );
memcpy( result + n1, str2, n2 + 1 );
}
return result;
}
int main(void)
{
char *result = concatenate( "Code ", "blocks" );
if ( result != NULL ) puts( result );
free( result );
return 0;
}
The program output is the same as shown above that is
Code blocks
Aside from the fact that your function should not return char but char*, the expression result[i++] = str1[i++]; is not correct it lacks a sequence point. Furthermore result is an unitialized pointer, it cannot hold any data, you would need to make it point to some valid memory location.
You could do something like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* concatenate(const char* str1, const char* str2 ){
char* result = malloc(strlen(str1) + strlen(str2) + 1);
if (result){
char* temp = result;
while (*str1 != '\0'){
*temp++ = *str1++;
}
while (*str2 != '\0'){
*temp++ = *str2++;
}
*temp = '\0'; // don't forget to null terminate the string
}
return result; // if memory allocation fails a null pointer is returned
}
The direct usage of the function in the printf statement will not allow you to free the memory and you would have a memory leak if the program didn't finish immediately, in these cases it's best to have the returned pointer assigned as to not lose track of the allocated memory:
int main(void){
char *result = concatenate("Code", "blocks");
if(result){
printf("%s", result);
free(result);
}
return EXIT_SUCCESS;
}
I'm trying to write a function that removes whitesapces from a string and convert it to lower case.
My code below doesn't return anything. Why?
char *removeSpace(char *st);
int main(void){
char *x = "HeLLO WOrld ";
x = removeSpace(x);
printf("output: %s\n", x);
}
char *removeSpace(char *st)
{
int c = 0;
char *s = malloc(sizeof(strlen(st)+1));
for (int x = 0; x < strlen(st); x++)
{
if (st[x] != ' ')
{
s[x] = tolower(st[x]);
}
}
st= s;
st= s;
return st;
}
The malloc statement uses sizeof unnecessarily as mentioned in the comments. You also have an error in the assignment of characters to the new string:
s[x] = tolower(st[x]);
You use the same index to the new string s as the old string st. This isn't right as soon as you remove any spaces. So for example indexes 0 through 4 line up between the two strings as you copy hello but then you skip a space at index 5 and then you want to assign the w at st[6] to s[5]. This means you need a separate index to track where you are in the destination string. So you need something like this code, which cleans up malloc(), adds the missing header includes, and introduces a new index for the output string:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
char *removeSpace(char *st);
int main(void){
char *x = "HeLLO WOrld ";
x = removeSpace(x);
printf("output: %s\n", x);
}
char *removeSpace(char *st)
{
size_t len = strlen(st);
int newStrIdx = 0;
char *s = malloc(len+1);
for (int x = 0; x < len; x++)
{
if (st[x] != ' ')
{
s[newStrIdx++] = tolower(st[x]);
}
}
s[newStrIdx] = '\0';
return s;
}
Oh, and you forgot the null-terminate the output string, which I added at the end.
char *s = malloc(sizeof(strlen(st)+1));
you have a couple of nested expressions, and you jumped exactly the wrong way in the comment thread (I guess it was 50:50).
strlen(st) is the number of characters in the string st
strlen(st)+1 is the correct number of characters to allocate for a copy
... looking good so far!
sizeof(strlen(st)+1) is the size in bytes required to represent the type of that value. So if size_t is an 4-byte unsigned int, this sizeof expression is just 4.
The value of the string length is thrown away at this point.
Now, you want to allocate enough bytes for the string, not enough bytes to save the string's length as a size_t value. Just remove the sizeof entirely.
Oh, and also - st = s doesn't do anything here. The variable st is local inside the function, and doesn't affect anything outside. Returning s is sufficient.
For starters if you want to create a copy of a string then the function declaration shall look like
char * removeSpace( const char *st);
that is the original string is not changed within the function.
And as you are passing to the function a string literal
char *x = "HeLLO WOrld ";
x = removeSpace(x);
then indeed it may not be changed within the function. Any attempt to change a string literal results in undefined behavior.
The expression used in the call of malloc
sizeof(strlen(st)+1)
is equivalent to the expression
sizeof( size_t )
due to the fact that the function strlen has the return type size_t.
So this expression does not yield the length of the source string.
Moreover there is no need to allocate a string with the size equal to the size of the source string because the destination string can have much less characters (due to removing spaces) than the source string.
The assignment in the if statement
if (st[x] != ' ')
{
s[x] = tolower(st[x]);
}
uses an invalid index in the expression s[x]. That is as a result the destination string will contain gaps with uninitialized characters.
Also the terminating zero character '\0' is not appended to the destination string
Take into account that the set of white space characters includes other characters as for example the tab character '\t' apart from the space character ' '.
The function can be defined the following way.
char * removeSpace( const char *st )
{
size_t n = 0;
for ( const char *src = st; *src; ++src )
{
if ( !isspace( ( unsigned char )*src ) ) ++src;
}
char *result = malloc( n + 1 );
result[n] = '\0';
for ( char *dsn = result; *st; ++st )
{
if ( !isspace( ( unsigned char )*st ) )
{
*dsn++ = tolower( ( unsigned char )*st );
}
}
return result;
}
And the function can be called like
char *st = "HeLLO WOrld ";
char *dsn = removeSpace( st );
puts( dsn );
free( dsn );
Here is a demonstrative program.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
char * removeSpace( const char *st )
{
size_t n = 0;
for ( const char *src = st; *src; ++src )
{
if ( !isspace( ( unsigned char )*src ) ) ++src;
}
char *result = malloc( n + 1 );
result[n] = '\0';
for ( char *dsn = result; *st; ++st )
{
if ( !isspace( ( unsigned char )*st ) )
{
*dsn++ = tolower( ( unsigned char )*st );
}
}
return result;
}
int main(void)
{
char *st = "HeLLO WOrld ";
char *dsn = removeSpace( st );
puts( dsn );
free( dsn );
return 0;
}
Its output is
helloworld
I'm trying to reverse a string, but it just stays the same. I don't use any modules except <string.h> and <stdio.h>.
void rev(s){
char i, temp;
char *sf = s;
char ri = strlen((s) - 1);
char *sl = &s[ri];
for (i = 0; i < ri; i++){
if (*sf != *sl){
temp = *sf++;
s[i] = *sl--; //
s[ri--] = temp; //those two seems to be getting new characters, but it won't
}
else {
ri--;
sf++;
sl--;
}
}
printf("%s", s);
}
The function will not compile at least because the parameter does not have a type specifier.
void rev(s){
The type char has a little range of acceptable values. So you shall not use it for calculating the length of a string.
The call of strlen in this declaration
char ri = strlen((s) - 1);
invokes undefined behavior. It seems you mean
char ri = strlen(s) - 1;
that also can invoke undefined behavior for an empty string.
This loop
for (i = 0; i < ri; i++){
does not use pointers.
The function can be defined the following way as it is shown in the demonsytrative program below.
#include <stdio.h>
#include <string.h>
char * reverse( char *s )
{
if ( *s )
{
for ( char *first = s, *last = s + strlen( s ); first < --last; ++first )
{
char c = *first;
*first = *last;
*last = c;
}
}
return s;
}
int main( void )
{
char s1[] = "1";
char s2[] = "12";
char s3[] = "123";
puts( reverse( s1 ) );
puts( reverse( s2 ) );
puts( reverse( s3 ) );
}
The program output is
1
21
321
A simple solution:
char *sl = sf;
while (*sl != 0)
++ sl;
-- sl;
while (sf < sl)
{
char c = *sf;
*sf = *sl;
*sl = c;
++sf, --sl;
}
Find the end of the string by skipping all characters until you find the NUL (zero) character.
Then step back one character (decrement sl) so that you have pointers to the first and the last character of the string.
Then walk both pointers towards one another and swap characters until the pointers meet or cross.
Your code has plenty of issues (bugs 🐛):
char ri = strlen((s) - 1); has to be size_t ri = strlen((s)) - 1;
Other code is very hard to analyze as you use not self explanatory variable names.
Here you have a bit more simple code and much easier to analyse.
char *reverseString(char *str)
{
char *wrk = str, *end;
if(str && *str)
{
end = str + strlen(str) - 1;
while(end > wrk)
{
char temp = *wrk;
*wrk++ = *end;
*end-- = temp;
}
}
return str;
}
int main(void)
{
char str[] = "1234567890";
printf("reversed: %s\n", reverseString(str));
}
I have an array of pointers to strings.
char **array;
I declare it this way and not char *array[N] because this array won't have a static number of elements.
Declaring the array this way, I will probably have to realloc the sizeof it every time I add a new element (pointer to string).
int main(void)
{
char **array;
char *word = "lolol";
char *word2 = "blabla";
return 0;
}
Could you give me an example on how I should "create space" in the array in order to store pointers to these strings?
The best way of doing it is probably by making a struct
This way, you can resize it, and add as many strings as you want without needing to choose a specific size.
Note: setting the string_array's capacity and size to 0 is necessary for it to work.
You could do it by a function like this instead:
void load_array(string_array *array)
{
array->size = 0;
array->capacity = 0;
}
And call it like this:
load_array(&my_array);
Note, when getting the value from one of these arrays using [], you must call it like this:
my_array.arr[index]
This is because you must refer to the pointer in the array struct, which is as arr (char **)
I have tested the below, and it works perfectly.
# include <stdio.h>
typedef struct string_array
{
char **arr;
unsigned capacity, size;
} string_array;
void add_to_array(string_array *array, char *str)
{
if(array->capacity == 0)
{
array->arr = (char **)malloc((array->capacity = 3) * sizeof(char *));
array->arr[array->size++] = str;
}
else if(array->capacity == array->size)
{
array->arr = (char **)realloc(array->arr, (array->capacity *= 1.5) * sizeof(char *));
array->arr[array->size++] = str;
}
else
{
array->arr[array->size++] = str;
}
}
int main(void)
{
char *str1 = "Hello World";
char *str2 = "Hello World2";
char *str3 = "Hello World3";
char *str4 = "Hello World4";
char *str5 = "Hello World5";
string_array my_array;
my_array.capacity = 0;
my_array.size = 0;
add_to_array(&my_array, str1);
add_to_array(&my_array, str2);
add_to_array(&my_array, str3);
add_to_array(&my_array, str4);
add_to_array(&my_array, str5);
// and so on
for (int i = 0; i < my_array.size; ++i)
{
printf(my_array.arr[i]);
printf("\n");
}
free(my_array.arr);
getchar(); // this means pressing enter closes the console
return (0);
}
Here is a demonstrative program
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
size_t N = 2;
char **array = malloc( N * sizeof( char * ) );
if ( !array ) return 1;
char *word = "lolol";
char *word2 = "blabla";
array[0] = word;
array[1] = word2;
char *word3 = "Hello";
++N;
array = realloc( array, N * sizeof( char * ) );
if ( !array ) return 2;
array[2] = word3;
for ( size_t i = 0; i < N; i++ ) puts( array[i] );
free( array );
return 0;
}
The program output is
lolol
blabla
Hello
Simply allocate some room for pointers in your array, and free it when you're done.
char *word = "lolol";
char *word2 = "blabla";
char** array = malloc(2*sizeof(char*));
array[0] = word;
array[1] = word2;
free(array);
You can change that 2*sizeof(char*) to a N*sizeof(char*) if you want more elements.