michael
michael

Reputation: 87

C input issue when creating new data structure

I have a simple program here where function create_truck needs to return truck data structure which I named as lol, and my question is that why this line struct truck lol = { asd, length, weight, crg }; won't take asd as an input. This needs to be done without dynamical allocation and copy of a string 'name' is needed to be done. And I have to keep the function parameters as they are + the data structures cargo and truck are actually in header file but just to not be too complicated I posted this code like this.

My code:

//Cargo: what the truck is carrying
struct cargo {
    const char *title;
    int quantity;
    double weight;
};

// Define the truck structure here
struct truck {
    char *name;
    double length;
    double weight;
    struct cargo crg;
};


struct truck create_truck(const char *name, double length, double weight,
    struct cargo crg) {
    char asd[31];
    strncpy(asd, name, 31);

/*here is my problem, this command below wont take my string asd
  as a valid input*/
    struct truck lol = { asd, length, weight, crg };
    return lol;
}

/*This function is just for printing the parts of the data structure I made*/
void print_truck(const struct truck *car) {
    printf("%s\n", car->name);
    printf("%.1lf\n", car->length);
    printf("%.1lf\n", car->weight);
    printf("%s\n", car->crg.title);
    printf("%d\n", car->crg.quantity);
    printf("%.1lf\n", car->crg.weight);

}

int main()
{
    /* testing exercise. Feel free to modify */
    struct cargo c = { "Bananas", 10000, 1500 };

    struct truck t = create_truck("Mercedes-Benz Actros", 12.0, 12.5, c);

    print_truck(&t);

    return 0;
}

Upvotes: 0

Views: 129

Answers (3)

sg7
sg7

Reputation: 6298

The problem with your approach:

char asd[31];
strncpy(asd, name, 31);

is that asd will not exist once the function returns since asd is just a local array.

The solution given by Eziz is also wrong.

struct truck create_truck(const char *name, double length, double weight, struct cargo crg) {
    char *asd;

    if( (asd = malloc( strlen(name)+1 )) == NULL ) {
        printf( "Memory error!\n" );
        exit( 0 );
    }
    strcpy(asd, name);

    struct truck lol = { asd, length, weight, crg };

    free(asd); // free here (wrong)

    return lol;
}

Once we free asd your char * name in struct truck {

char *name; // POINTER TO A MEMORY
//...
}   

points to the freed memory!

What you need is to make sure that char *name points to valid memory holding the name, than all what you need is:

struct truck create_truck(char *name, double length, double weight, struct cargo crg)
{
    struct truck lol = { name, length, weight, crg };
    return lol;
}

The test program is below, let me know if it works for you.

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

//Cargo: what the truck is carrying
struct cargo {
    const char *title;
    int quantity;
    double weight;
};

// Define the truck structure here
struct truck {
    char *name;       // has to point to a valid memory holding the name
    double length;
    double weight;
    struct cargo crg;
};

struct truck create_truck(char *name, double length, double weight, struct cargo crg)
{
    struct truck lol = { name, length, weight, crg };
    return lol;
}

/*This function is just for printing the parts of the data structure I made*/
void print_truck(const struct truck *car) {

    printf("%s\n", car->name);
    printf("%.1lf\n", car->length);
    printf("%.1lf\n", car->weight);
    printf("%s\n", car->crg.title);
    printf("%d\n", car->crg.quantity);
    printf("%.1lf\n\n", car->crg.weight);
}

int main()
{
    struct cargo c = { "Bananas", 10000, 1500 };
    //1.    
    char name1[] = { 'F', 'O', 'R','D', 0};
    //2.
    char *name2 = "TOYOTA"; 
    //3.
    char *name3 = (char[]){'M', 'I', 'N', 'I', 0};
    //4.
    size_t len4 = strlen("LADA") + 1;
    char *name4 = malloc(len4*sizeof(char));
    strcpy(name4,"LADA");  

    //5. warning: strdup is not part of the C or C++ standard, it's a POSIX function.
    char *name5 = strdup("HONDA");  

    // 0.
    struct truck t = create_truck("Mercedes-Benz Actros", 12.0, 12.5, c);
    print_truck(&t);

    // 1.
    struct truck t1 = create_truck(name1, 12.0, 12.5, c);
    print_truck(&t1);

    // 2.
    struct truck t2 = create_truck(name2, 12.0, 12.5, c);
    print_truck(&t2);

    // 3.
    struct truck t3 = create_truck(name3, 12.0, 12.5, c);
    print_truck(&t3);

    // 4.
    struct truck t4 = create_truck(name4, 12.0, 12.5, c);
    print_truck(&t4);

    // 5.
    struct truck t5 = create_truck(name5, 12.0, 12.5, c);
    print_truck(&t5);


    free(name4);
    free(name5);

    return 0;
}

Output of the program:

Mercedes-Benz Actros                                                                                                         
12.0                                                                                                                         
12.5                                                                                                                         
Bananas                                                                                                                      
10000                                                                                                                        
1500.0                                                                                                                       

FORD                                                                                                                         
12.0                                                                                                                         
12.5                                                                                                                         
Bananas                                                                                                                      
10000                                                                                                                        
1500.0                                                                                                                       

TOYOTA                                                                                                                       
12.0                                                                                                                         
12.5                                                                                                                         
Bananas                                                                                                                      
10000                                                                                                                        
1500.0 

MINI                                                                                                                         
12.0                                                                                                                         
12.5                                                                                                                         
Bananas                                                                                                                      
10000                                                                                                                        
1500.0                                                                                                                       

LADA                                                                                                                         
12.0                                                                                                                         
12.5                                                                                                                         
Bananas                                                                                                                      
10000                                                                                                                        
1500.0                                                                                                                       

HONDA                                                                                                                        
12.0                                                                                                                         
12.5                                                                                                                         
Bananas                                                                                                                      
10000                                                                                                                        
1500.0    

Upvotes: 1

Eziz Durdyyev
Eziz Durdyyev

Reputation: 1158

I think the problem is in strncpy. If you get the name of truck with dynamic memory allocation, the function works fine:

struct truck create_truck(const char *name, double length, double weight, struct cargo crg) {
    char *asd;

    if( (asd = malloc( strlen(name)+1 )) == NULL ) {
        printf( "Memory error!\n" );
        exit( 0 );
    }

    strcpy(asd, name);

    struct truck lol = { asd, length, weight, crg };
    free(asd); // free here
    return lol;
}

Upvotes: 1

Fabel
Fabel

Reputation: 1761

If you allocate struct truck on the stack in main() you should provide a pointer to it in the call to crate_truck() (and perhaps rename create_truck() to initaialize_truck() since it doesn't actually create it). Something like this:

void initialize_truck(struct truck* lol,const char *name, double length, double weight,struct cargo* crg){
    lol->name = strdup(name);
    lol->length = length;
    lol->weight = weight;
    /* This is kind of a hack, you should either deep copy or just have a pointer to cargo. */
    memcpy(&lol->crg,crg,sizeof(struct cargo));
}

main(){
    struct cargo c = { "Bananas", 10000, 1500 };
    struct truck t;
    initialize_truck(&t, "Mercedes-Benz Actros", 12.0, 12.5, &c);
    print_truck(&t);
    return 0;
}

Or, as an alternative, dymamically allocate struct truck instead of putting it on the stack:

struct truck create_truck(const char *name, double length, double weight,struct cargo* crg){
    struct truck* lol = (struct truck*)malloc(sizeof(struct truck));
    lol->name = strdup(name);
    lol->length = length;
    lol->weight = weight;
    /* This is kind of a hack, you should either deep copy or just have a pointer to cargo. */
    memcpy(&lol->crg,crg,sizeof(struct cargo));
    return lol;
}

main(){
    struct cargo c = { "Bananas", 10000, 1500 };
    struct truck* t = create_truck("Mercedes-Benz Actros", 12.0, 12.5, &c);
    print_truck(t);
    return 0;
}

Upvotes: 0

Related Questions