Home > Blockchain >  How to work with C struct string variables of unknown sizes?
How to work with C struct string variables of unknown sizes?

Time:09-06

I am trying to use a struct that has strings of an unknown size, but can't get things to work...

Assume with the text below that you don't know what the lengths of a_word and another_word will be, meaning that you can't define the char array length when specifying the struct. So after declaring the struct, I want to assign these unknown strings to its attributes. Then I want to print the attributes and finally free the memory.

However, as it stands only the number prints out and this is weird (i.e. not 100, changes each time I run the code). After that I get an AddressSanitizer:DEADLYSIGNAL error.

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

typedef struct Object {
    unsigned short a_number;
    char *a_word;
    char *another_word;
} Object;


Object *create_object() {
    Object my_object;
    Object* p_my_object = &my_object;
    return p_my_object;
}


void set_word(Object **my_object, const char *a_word) {
  (*my_object)->a_word = malloc(strlen(a_word)   1);
  strncpy((*my_object)->a_word, a_word, sizeof((*my_object)->a_word)   1);
}

void set_another_word(Object **my_object, const char *another_word) {
  (*my_object)->another_word = malloc(strlen(another_word)   1);
  strncpy((*my_object)->another_word, another_word, sizeof((*my_object)->another_word)   1);
}

void set_number(Object **my_object, unsigned short a_number) {
  (*my_object)->a_number = a_number;
}


void clear_memory(Object **my_object){
    free((*my_object)->a_word);
    free((*my_object)->another_word);
}


int main()
{
    unsigned short a_number = 100;
    char *a_word = "apple";
    char *another_word = "banana";
    Object *my_object;
    
    my_object = create_object();
    set_word(&my_object, a_word);
    set_another_word(&my_object, another_word);
    set_number(&my_object, a_number);
    
    printf("a_number: %hu\n", my_object->a_number);
    printf("a_word: %s\n", my_object->a_word);
    printf("another_word: %s\n", my_object->another_word);
    
    clear_memory(&my_object);

    return 0;
}

Can anyone see what I'm doing wrong here?

CodePudding user response:

The two main problems are:

  1. create_object() returns a pointer to a local variable which is out of scope when the function returns. I changed it to just return the object by value. The other valid choice is to use malloc() to heap allocating the object instead (which you now have to free at some point). Also changed the function signatures to just take an Object * instead of a Object ** as the latter is not needed here.
  2. set_word() and set_another_word() should use strlen() instead of sizeof() for 3rd argument of strncpy(), however, as @ n. 1.8e9-where's-my-share m. pointers out it's better to use strcpy().

and these minor issues:

  1. format string %hu doesn't match argument. I changed it here.
  2. (not fixed) set_word() and set_another_word() should be refactored to eliminate duplicate code, for instance, replacing both with a call to strdup().
  3. (advise) consider if writing a wrapper function for each attribute is a good design choice. I rarely do, i.e. only if I want to keep the struct an implementation detail, and even then I focus on what I want to do rather than mechanical mapping of each attribute to a pair of functions (get and set).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct Object {
    int a_number;
    char *a_word;
    char *another_word;
} Object;

Object create_object() {
    return (Object) { 0 };
}

void set_word(Object *my_object, const char *a_word) {
    my_object->a_word = malloc(strlen(a_word)   1);
    strcpy(my_object->a_word, a_word);
}

void set_another_word(Object *my_object, const char *another_word) {
    my_object->another_word = malloc(strlen(another_word)   1);
    strcpy(my_object->another_word, another_word);
    
}

void set_number(Object *my_object, unsigned short a_number) {
    my_object->a_number = a_number;
}

void clear_memory(Object *my_object){
    free(my_object->a_word);
    free(my_object->another_word);
}

int main() {
    unsigned short a_number = 100;
    char *a_word = "apple";
    char *another_word = "banana";
    Object my_object;

    my_object = create_object();
    set_word(&my_object, a_word);
    set_another_word(&my_object, another_word);
    set_number(&my_object, a_number);

    printf("a_number: %d\n", my_object.a_number);
    printf("a_word: %s\n", my_object.a_word);
    printf("another_word: %s\n", my_object.another_word);

    clear_memory(&my_object);

    return 0;
}

and the result of running the program:

a_number: 100
a_word: apple
another_word: banana
  • Related