Home > Software engineering >  why does strcat not work inside function?
why does strcat not work inside function?

Time:09-02

hi i'm trying to write a function that get 3 words, concatenate them to one word and print the word reverse. i can't put the concatenated word into the ptr w1 in concatWords function. another question - should i put '\0' in the end of every word? can someone review my code? thanks!

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define N 10

void initWords(char *w1, char *w2, char *w3) {
    printf("Enter first word:\n");
    scanf("s", w1);
    printf("Enter second word:\n");
    scanf("s", w2);
    printf("Enter third word:\n");
    scanf("s", w3);
   
}
char* concatWords(char *w1, char *w2, char *w3) {
    int len = strlen(w1)   strlen(w2)   strlen(w3);
    w1 = (char*)malloc(sizeof(char) * len);
    strcat(w1, w2);
    strcat(w1, w3);
    return w1;
}

void printReversedWord(char *word) {
    int len = strlen(word);
    for (int i = len - 1; i >=0; i--) {
        printf("%c", word);
    } 
}

int main()
{
    char word1[N 1];
    char word2[N 1];
    char word3[N 1];
    char* longWord;
    initWords(word1, word2, word3);
    longWord = concatWords(word1, word2, word3);
    printReversedWord(longWord);
    free(longWord);
    return 0;
}

CodePudding user response:

You allocate memory that you assign to w1. Whatever w1 was pointing at can therefore not be included in the final string. You need a separate variable for where to put the final result.

Example:

char *concatWords(char *w1, char *w2, char *w3) {
    size_t w1len = strlen(w1);
    size_t w2len = strlen(w2);
    size_t w3len = strlen(w3);

    // the final result will be stored in memory pointed out by `res`:
    char *res = malloc(w1len   w2len   w3len   1);  //  1 for null terminator
    if (res) {
        // copy the three strings where they belong:
        memcpy(res, w1, w1len);
        memcpy(res   w1len, w2, w2len);
        memcpy(res   w1len   w2len, w3, w3len   1); //  1 for null terminator
    }
    return res;
}

Another issue: printReversedWord is missing the subscript operator on word:

void printReversedWord(char *word) {
    for (size_t i = strlen(word); i-- > 0;) {
        printf("%c", word[i]);                // <- here
    }
}

Demo

CodePudding user response:

The function strcat deals with strings. That means that the both function arguments shall point to strings. And the function also builds a string.

Also as your function does not change passed strings then its parameters should have qualifier const. And the function shall build a new string. Otherwise after this statement

w1 = (char*)malloc(sizeof(char) * len);

the first passed string is lost.

The function can look the following way

char * concatWords( const char *w1, const char *w2, const char *w3 ) 
{
    size_t len = strlen( w1 )   strlen( w2 )   strlen( w3 );
    char *result = malloc( len    1 );

    if ( result != NULL )
    {
        strcpy( result, w1 );
        strcat( result, w2 );
        strcat( result, w3 );
    }

    return result;
}

In turn the function printReversedWord can look the following way/ Pay attention to that your function implementation has a bug in this statement

printf("%c", word);

You have to write

printf("%c", word[i]);

Here is the updated function definition.

void printReversedWord( const char *word ) 
{
    size_t len = strlen( word );

    while ( len != 0 )
    {
        putchar( word[--len] );
    }

    putchar( '\n' );
}

In main you should write

initWords( word1, word2, word3 );

longWord = concatWords(word1, word2, word3);

if ( longWord != NULL ) printReversedWord(longWord);

free( longWord );

CodePudding user response:

char* concatWords(char *w1, char *w2, char *w3) {
    int len = strlen(w1)   strlen(w2)   strlen(w3);
    w1 = (char*)malloc(sizeof(char) * len);
    strcat(w1, w2);
    strcat(w1, w3);
    return w1;
}

This method:

  • allocates memory that is not zeroed out, which will make it impossible to "cat" to it, because that assumes the string is null-terminated.
  • allocates memory and then overwrites the pointer that points to the first word. That would be lost.
  • allocates only memory for the three words, but misses the final zero that needs to be written to a null-terminated string
  • does not communicate clearly, which parameters will or will not be changed be the function

So to fix this:

char* concatWords(const char* w1, const char* w2, const char* w3) {
    int len = strlen(w1)   strlen(w2)   strlen(w3);
    char* all = calloc(len   1, sizeof(char));
    strcat(all, w1);
    strcat(all, w2);
    strcat(all, w3);
    return all;
}

CodePudding user response:

The max length of each string is defined in a globally available token... Why not use it (and temporarily use a bit too much dynamic memory)?

char* concatWords(char *w1, char *w2, char *w3) {
    char *p = (char*)malloc( (3*N 1) * sizeof *p );
    if( p )
        sprintf( p, "%s%s%s", w1, w2, w3 );

    return p;
}

One could also add checking that all 3 incoming pointers are not NULL...

CodePudding user response:

char* concatWords(char *w1, char *w2, char *w3) {
    int len = strlen(w1)   strlen(w2)   strlen(w3);
    w1 = (char*)malloc(sizeof(char) * len);
    strcat(w1, w2);
    strcat(w1, w3);
    return w1;
}

This function needs a fair bit of work. I'm assuming you want to allocate a new string sufficiently large for the job, concatenate w1, w2 and w3 into it, and return that new string.

Firstly, you overwrote the pointer for w1 in this line:

w1 = (char*)malloc(sizeof(char) * len);

So (in that function) you've now lost whatever was pointed to by w1, because w1 is now pointed to newly-allocated memory.

Secondly, you've not allocated enough memory to store the string: you need an extra 1 to include the terminal NUL character.

The original values of w1, w2 and w3 passed into the function were cast to (char *) from the base addresses of char[] arrays, so you can't use w1 = realloc(w1, len 1); - you'll need a new variable to store the new pointer.

Your concatWords() function should look like this:

char* concatWords(const char * const w1,
                  const char * const w2,
                  const char * const w3) {
    int len = strlen(w1)   strlen(w2)   strlen(w3)   1; // Note the  1!
    new_w = (char*)malloc(sizeof(char) * len);
    strcpy(new_w, w1);
    strcat(new_w, w2);
    strcat(new_w, w3);
    return new_w;
}

Note that I've changed the function's parameter types, so that you don't accidentally change the values of the w1, w2 or w3 pointers, or the memory they point to. Always use minimum viable permissions, to prevent the risk of memory corruption. In C terms, if you can const it, const it!

Your printReversedWord(char *word) function won't work either. You're passing word, not the contents of the memory it's pointing to. You never use the index variable i!

This will have the effect of passing either the first or the last byte of the pointer value as the character to print, depending whether your CPU's bigendian or littleendian.

So if word's value was 0x12345678 (the location of the first character in the string it points to), you're either printing 0x12 or 0x78 over and over again instead of the reversed contents of word.

It should be (something like):

void printReversedWord(const char * const word) {
    int len = strlen(word);
    for (int i = len - 1; i >=0; i--) {
        printf("%c", word[i]);
    } 
}

Note the [i] in the printf() argument. It indexes into the char array pointed to by word. Note also (again) the improvement in the parameter type.

Finally, looking at:

#define N 10
void initWords(char *w1, char *w2, char *w3) {
    printf("Enter first word:\n");
    scanf("s", w1);
    printf("Enter second word:\n");
    scanf("s", w2);
    printf("Enter third word:\n");
    scanf("s", w3);
   
}

You've defined N, but then explicitly embedded 10 in the scanf() format strings. What happens if you change the value of N at a later point?

I'll leave the solution for that as an exercise for the student. :)

  • Related