Allocating memory for string pointers?

43 views Asked by At

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;  
 
}
2

There are 2 answers

0
Remy Lebeau On

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); 
0
Vlad from Moscow On

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 );