Jetson
Jetson

Reputation: 25

Returning an array of pointers to `char`

This program should concatenate strings, But I don't know how return the string array back to main.

char **conca(char *a[], int n)
{

char buff[200];

char **conc[n];
for (int i = 0; i < n; i++)
{
    strcpy(buff,a[i]);
    strcat(buff,"-");
    int l = strlen(buff);
    *conc[i] = malloc((l+1)*sizeof(char));
    strcpy(*conc[i],buff);
}

return *conc;

In main.c:

char **conca(char *a[], int n);

int main(int argc, char *argv[])
{
    if(argc == 1)
    {
        printf("Uso: %s <stringa> <stringa> ... <stringa> \n",argv[0]);
        return 1;
    }

    int dim = argc - 1;

    int pos = 0;
    char *array[dim];

    for(int i = 1; i <= dim; i++ )
    {
        array[pos] = malloc((strlen(argv[i])+1)*sizeof(char));
        strcpy(array[pos],argv[i]);
        pos++;
    }

    char **f = conca(array, dim);
}

The program triggers a segmentation fault (core dump).

How can I print the concatenated string in main?

Upvotes: 0

Views: 121

Answers (4)

user3629249
user3629249

Reputation: 16540

the following code:

  1. cleanly compiles
  2. performs the desired functionality
  3. properly outputs error messages to stderr
  4. properly checks for errors
  5. includes the proper #include statements
  6. is appropriately commented
  7. contains some the original posted code as comments to highlite where changes were made
  8. avoids unnecessary variables
  9. displays the resulting concatenated string
  10. cleans up after itself

and now the code

#include <stdio.h>  // printf(), fprintf()
#include <stdlib.h> // exit(), EXIT_FAILURE, malloc(), realloc(), free()
#include <string.h> // strlen(), strcat()


//char **conca(char *a[], int n);
// function prototypes
char *concat(char *argv[], int argc);

int main(int argc, char *argv[])
{
    if(argc == 1)
    {
        fprintf( stderr, "Uso: %s <stringa> <stringa> ... <stringa> \n",argv[0]);
        //printf("Uso: %s <stringa> <stringa> ... <stringa> \n",argv[0]);
        exit( EXIT_FAILURE );
        //return 1;
    }

    char *newCat = concat( argv, argc );

    printf( "%s\n", newCat );
    free( newCat );
} // end function: main


char *concat(char *argv[], int argc)
{

    char *newString = malloc(1);
    if( !newString )
    { // then malloc failed
        perror( "malloc failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, malloc successful
    newString[0] = '\0';

    for( int i = 1; i <= argc; i++ )
    //for(int i = 1; i <= dim; i++ )
    {
        char * tempptr = realloc( newString, strlen( newString) + strlen(argv[i])+2 );
        if( !tempptr )
        { // then realloc failed
             perror( "realloc failed" );
             free( newString );
             exit( EXIT_FAILURE );
        }

        // implied else, realloc successful

        newString = tempptr;
        //array[pos] = malloc((strlen(argv[i])+1)*sizeof(char));
        //strcpy(array[pos],argv[i]);
        strcat( newString, argv[i] );

        // avoid a trailing '-' in final string
        if( i < (argc-1) )
        { 
            strcat( newString, "-" );
        }
    } // end for

    return newString;
} // end function: concat

Upvotes: 0

RoadRunner
RoadRunner

Reputation: 26335

Instead of returning char **, You should return char *.

There is also no error checking on malloc, which is needed since you can return a NULL pointer if unsuccessful.

Here is an example that shows this:

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

char *join(char *argv[], int n);

int main(int argc, char *argv[]){
    char *result;

    if(argc == 1){
        printf("Uso: %s <stringa> <stringa> ... <stringa> \n", argv[0]);
        return 1;
    }

    result = join(argv, argc);
    printf("%s\n", result);

    free(result);
    result = NULL;

    return 0;
}

char *join(char *argv[], int n) {
    int i;
    const char *sep = "-";
    char *string;
    size_t strsize = 0;

    for (i = 1; i < n; i++) {
        strsize += strlen(argv[i])+1;
    }

    string = malloc(strsize);
    if (!string) {
        printf("Cannot allocate memory for string.\n");
        exit(EXIT_FAILURE);
    }

    *string = '\0';
    for (i = 1; i < n; i++) {
        strcat(string, argv[i]);
        if (i < n-1) {
            strcat(string, sep);
        }
    }
    return string;
}

Input:

$ gcc -Wall -Wextra -Wpedantic -std=c99 -o concat concat.c

$ ./concat Always check return of malloc

Output:

Always-check-return-of-malloc

Upvotes: 0

BLUEPIXY
BLUEPIXY

Reputation: 40155

You need return char* instead of array of pointer to char.
Like this

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

char *join(char *a[], int n, char sep){
    size_t lens[n], total_length = 0;

    for (int i = 0; i < n; i++){
        total_length += (lens[i] = strlen(a[i]));
    }
    total_length += n;//sep * (n-1) + NUL

    char *ret = malloc(total_length);
    char *wk = ret;

    for (int i = 0; i < n; i++){
        if(i)
            *wk++ = sep;
        memcpy(wk, a[i], lens[i]);
        wk += lens[i];
    }
    *wk = 0;

    return ret;
}

int main(int argc, char *argv[]){
    if(argc == 1){
        printf("Uso: %s <stringa> <stringa> ... <stringa> \n", argv[0]);
        return 1;
    }

    int dim = argc - 1;
    char *concata = join(argv+1, dim, '-');
    puts(concata);
    free(concata);
}

Upvotes: 2

Sumit Gemini
Sumit Gemini

Reputation: 1836

Reason of segfault is you can not initialize memory for *conc[i] like that :

*conc[i] = malloc((l+1)*sizeof(char))

instead you have to do

conc[i] = malloc((l+1)*sizeof(char))

But you have another problem here. You're declaring the array as a local variable. conc is an array of pointers which is stored in conca()'s stack frame, so this is, technically speaking, undefined behavior. The solution is to change conc to a char ** and use malloc() to allocate the whole array (and remember to free it later)

So i modified your char **conca(char *a[], int n) function. so i used **conc instead of array of pointer.

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

char **conca(char *a[], int n)
{

char buff[200];

char **conc = (char **)malloc(n*sizeof(char *));
int i=0;
for (i = 0; i < n; i++)
{
    strcpy(buff,a[i]);
    strcat(buff,"-");

    int l = strlen(buff);
    conc[i]=(char *)malloc((l+1)*sizeof(char));
    strcpy(conc[i],buff);
}

return conc;
}

int main(int argc, char *argv[])
{
        if(argc == 1)
        {
                printf("Uso: %s <stringa> <stringa> ... <stringa> \n",argv[0]);
                return 1;
        }

        int dim = argc - 1;

        int pos = 0;
        char *array[dim];
        int i=0;
        for(i = 1; i <= dim; i++ )
        {
                array[pos] = malloc((strlen(argv[i])+1)*sizeof(char));
                strcpy(array[pos],argv[i]);
                pos++;
                pos++;
        }
        char **f = conca(array, dim);

        for(i=0;i<dim;i++)
        printf("%s",f[i]);

        printf("\n\n");
}

Upvotes: 0

Related Questions