HelpMyC
HelpMyC

Reputation: 11

Saving a string inside a struct in C

Hello I am new to c programming and while trying structs with different data types in my code

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

struct myType
{
    int imInteger;
    float imFloat;
    char imChar;
    char imString[33];
};

int main()
{
    struct myType example;

    example.imInteger = 4;
    example.imFloat = 3.141592;
    example.imChar = "h";
    char exampleChar = "g";
    example.imString = "Hello World";
    char exampleString[33] = "Goodbye World";

    printf("My data types are:\n");
    printf("\t Int: %d\n", example.imInteger);
    printf("\t Float: %.4f\n", example.imFloat);
    printf("\t Char: %c\n", example.imChar);
    printf("\t Example: %c\n", exampleChar);
    printf("\t String: %s\n", example.imString);
    printf("\t Example: %s\n", exampleString);
    return 0;
}

I get the following error

,,error copy.c: In function 'main':
error copy.c:18:20: warning: assignment to 'char' from 'char *' makes integer from pointer without a cast [-Wint-conversion]
   18 |     example.imChar = "h";
      |                    ^
error copy.c:19:24: warning: initialization of 'char' from 'char *' makes integer from pointer without a cast [-Wint-conversion]
   19 |     char exampleChar = "g";
      |                        ^~~
error copy.c:20:22: error: assignment to expression with array type
   20 |     example.imString = "Hello World";
      |                      ^

My expected output would be:

My data types are:
         Int: 4
         Float: 3.1416
         Char: h
         Example: g
         String: Hello World
         Example: Goodbye World

In previous codes without structs I didn't have any troubles when declaring char and using strings, so if anyone could bring me help it would be really appreciated.

Thanks

Upvotes: 1

Views: 856

Answers (1)

D&#250;thomhas
D&#250;thomhas

Reputation: 10028

There are two ways to store a string in a struct:

Provide a fixed-length space

struct myType
{
    int imInteger;
    float imFloat;
    char imChar;
    char imString[33];  // strings may not be more than 32 characters long
};

Strings must be copied to the struct:

struct myType example = {0};

strncpy( example.imString, "Hello world", sizeof(example.imString) );
example.imString[sizeof(example.imString)-1] = '\0';  // make sure it is null-terminated

Use dynamically-allocated strings

struct myType
{
    int imInteger;
    float imFloat;
    char imChar;
    char * imString;  // strings may be any size, but must be managed
};

This is where strdup() is useful:

struct myType example = {0};

example.imString = strdup( "Hello world" );

You must be careful to free() it every time you touch it, though:

free( example.imString );
example.imString = strdup( "Goodbye world" );

free( example.imString );
// destroy example

Initialization matters

Notice that both times I explicitly initialized the struct to zeros? This is a good thing: for the first example you get an empty fixed-length string; for the second example you get a NULL pointer — both of which are good because they provide a consistent, observable state at all times (and let that free() work without error).

Life is easy if you create a constructor:

struct myType create_myType()
{
    ...
}

or:

struct myType * create_myType()
{
    ...
}

void free_myType( struct myType * x )
{
    free( x->imString );
    free( x );
}

Every time you create one, use the explicit constructor:

struct myType example = create_myType();

or:

struct myType * example = create_myType();

...

free_myType( example );

You can even specialize constructors for different types:

struct myType * create_int_myType( int x );
struct myType * create_float_myType( float x );

struct myType * create_string_myType( const char * s )
{
    struct myType * result = create_myType();
    result->imString = strdup( s );
    return result;
}

And so on.

Upvotes: 4

Related Questions