Home > Blockchain >  tolower for C-style strings strcpy doesn't work
tolower for C-style strings strcpy doesn't work

Time:03-29

I'm trying to perform case insensitive strcmp on full name string. I have a function to convert C-style strings to lowercase.

    char* toLowerCase(char* string){
    
        char *s = string;
        unsigned long int s_len = strlen(s);
        char sToLower[s_len];
    
        for (int i = 0; i < s_len; i  )
            sToLower[i] = tolower(s[i]);
        sToLower[s_len] = 0;
    
        s = sToLower;
        return s;
    }

but strcpy and strcat doesn't work. how to solve it?

        char fullName[1024] = "";
        strcpy(fullName, toLowerCase(p->data.firstName));
        strcat(fullName, toLowerCase(p->data.lastName));

CodePudding user response:

The function toLowerCase is incorrect because it returns a pointer to a local array that will not be alive after exiting the function. So using this pointer to access memory will invoke undefined behavior.

char* toLowerCase(char* string){
//...
char sToLower[s_len];
//...
s = sToLower;
return s;
}

Moreover the size of the local array is specified incorrectly

char sToLower[s_len];

you need declare it at least like

char sToLower[s_len   1];

to reserve memory for the terminating zero character '\0'.

Either you need to change the source string in place (but in this case the function may not be used with string literals) or you need within the function to create dynamically a new array and store there the source string converted to lower case.

For example

char* toLowerCase( const char* s )
{
    char *sToLower = malloc( strlen( s )   1 );

    if ( sToLower != NULL )
    {
        char *p = sToLower;
        while ( ( *p   = tolower( ( unsigned char )*s   ) ) != '\0' );
    }

    return sToLower;
}

You will need to free the allocated memory in the function for the returned string when the string will not be required any more.

Or the function can be declared with two parameters that specify the source array and the destination array like

char* toLowerCase( char *dsn, const char* src );

That is the user of the function must supply the destination array that will store the source string converted to lower case.

CodePudding user response:

Thanks Vlad from Moscow !!! This is my solution:

void toLowerCase(char* target, const char* source){
while ((*target   = tolower((unsigned char)*source  )) != '\0');}

        toLowerCase(fullname, p->data.firstName);
        toLowerCase(lastName, p->data.lastName);
        strcat(fullname, lastName);
        printf("%s", fullname);

CodePudding user response:

As pointed out already, a local variable inside a function seizes to exist outside function scope. You can either dynamically allocate memory for target-string(& free later) OR supply it during the call.

Since fullName is already available you can modify the toLowerCase() function as below:

#include <inttypes.h>

size_t toLowerCopy (char* dst, size_t dsize, const char* src) {
    if (!src || dsize < 2 || !dst) return 0L;

    const char* tmp = src;
    while (*tmp && --dsize)
        *dst   = tolower (*tmp  );
    *dst = '\0';
    return (tmp - src);
}

It's also mindful of destination buffer-size, counting terminal \0 char. You can call it for fullName as:


char fullName[1024];

size_t copied = toLowerCopy (fullName, sizeof(fullName), p->data.firstName);
// handle if (copied == 0)
size_t first_len = copied;
if (copied) fullName [copied  ] = ' ';  // first name was not empty (separator)
copied = toLowerCopy (fullName   copied, sizeof(fullName) - copied, p->data.lastName);
// handle if (copied == 0)
if (!copied) fullName[first_len] = '\0'; // second name was emtpy
  • Related