struct field changed but it isn't expected

Viewed 40

I'm trying to translate a sentence into morse code. I have a morse.txt file with this type of content :

'-','-','-','-','-',0, /* Caractère 0 */
'.','-','-','-','-',0, /* Caractère 1 */
'.','.','-','-','-',0, /* Caractère 2 */

In order to translate each letter from the sentence I thought about create a 2 dimension array in which we would find a letter and its translation in morse. Here's my struct

typedef struct
{
    char lettre;
    char *morse;
} t_morse;

I created a function returning that array :

t_morse *loadTab()
{
    t_morse *tabMorse = malloc(LETTER_NUMBER * sizeof(t_morse));

    ssize_t read;
    size_t len = 0;
    char index = 0, k = 0, j;
    char *line = NULL;
    FILE *f = fopen("morse.txt", "r");
    if (f == NULL)
    {
        fprintf(stderr, "Fichier : %s n'existe pas\n","morse.txt");
        exit(0);
    }
    while (read = getline(&line, &len, f) != -1 && line != NULL)
    {
        char *morse = malloc(6 * sizeof(char));
        char *stringfinal = malloc(50 * sizeof(char));

        strcpy(stringfinal, line);
        k = 0;
        for (j = 0; j < strlen(stringfinal); j++)
            if (stringfinal[j] == '-' || stringfinal[j] == '.')
                morse[k++] = stringfinal[j];
        tabMorse[index].morse = morse;
        tabMorse[index].lettre = index + 48;
        printf("lettre : %c, morse : %s\n", tabMorse[index].lettre, tabMorse[index].morse);
        index++;
        free(morse);
        free(stringfinal);
    }
    fclose(f);

    for (index = 0; index < LETTER_NUMBER; index++)
    {
        printf("toto %c : %s\n", tabMorse[index].lettre, tabMorse[index].morse);
    }

    return tabMorse;
}

But it doesn't as it would be : when executing the programm, the first printf (printf("lettre : %c, morse : %s\n", tabMorse[index].lettre, tabMorse[index].morse);) show me the thing that I want. However after this when I want to iterate through that array and display the structs, the letter field is the right but in the morse field I get a "" string, and I don't know why.

You can see below, a screen of the stdout when launching the program :

enter image description here enter image description here

Do you know why it acts like that ?

3 Answers

The immediate problem is that you call free(morse); around every iteration of the loop. So when you print it from the second loop the contents are undefined.

You also do not null terminate the morse[] string.

    tabMorse[index].morse = morse;
    ...
    free(morse);

Since tabMorse[index].morse is equal to morse, free(morse) is the same as free(tabMorse[index].morse), which is obviously not right.

You do not want to free the chunk of memory that you just stashed a pointer to. You need to keep it allocated so you can safely dereference the pointer later.

As others have noted (no use repeating), you cannot use pointers to heap memory that has been free()'d. (It's best to not duplicate pointers unless you really keep track of them.)

tabMorse[index].morse = morse;
/* 3 lines omitted */
free(morse);

Too much code hides problems such as this.

Take a step back and think about Morse Code. There are only two symbols, and no character is longer than 5 symbols (or is it 6 maximum?).

A byte (unsigned) has 8 bits that can be in one of two states.

Imagine "encoding" the Morse alphabet in the lowest bits of a byte, one byte per character. Because Morse code uses 1 to 5 symbols per character, another bit (on the left of the low bits) can be used as a flag meaning "the remaining bits on my right are to be used as 0=dot and 1=dash"... The Morse letter 'E' (one dot only) would be represented by 0b000000t0, where 't' would be the 'trigger' (always 1), and the lowest bit 0 would signify a single 'dot'.

The familiar "SOS" would be 0b00001000, 0b00001111, 0b00001000 ("... --- ...").

The code below has been adapted from something I wrote for Brail translation. The (incomplete) octal values in the table have NOT been checked as valid Brail but give you a start as to how you might, with the description above, encode 128 characters (7-bit ASCII) in Morse (replacing the Brail encoding). (The tables entries for 'S/s', 'O/o' and 'SP' have been adapted to be correct Morse characters.)

It seems this is a lot less code, and doesn't provide many corners for bugs to lurk.

void morsify( char c ) {
    unsigned char oct[] = { // TODO: adapt these values from Brail to Morse
    // CTRL codes
           0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    // CTRL codes
           0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    // punctuation
         000,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 002,   0,   0,   0,
    // punctuation & digits
           0, 001, 003, 011, 031, 021, 013, 033, 023, 012, 032,   0,   0,   0,   0,   0,
    // @ + A-O
           0, 001, 003, 011, 031, 021, 013, 033, 023, 012, 032, 005, 007, 015, 035, 017,
    // P-Z + braces
         017, 037, 027, 010, 036, 045, 047, 072, 055, 075, 065,   0,   0,   0,   0,   0,
    // ` + a-o
           0, 001, 003, 011, 031, 021, 013, 033, 023, 012, 032, 005, 007, 015, 035, 017,
    // p-z + braces
         017, 037, 027, 010, 036, 045, 047, 072, 055, 075, 065,   0,   0,   0,   0,   0,
    };

    bool trig = false;
    uint8_t morse = oct[ c ]; // fetch copy of bit pattern from table
    for( uint8_t i = 0x80; i; i >>= 1 )
        if( !trig && (i & morse) ) // keep scanning right until trigger bit encountered
            trig = true;
        else if( trig ) // output has been triggered
            putchar( i & morse ? '-' : '.' ); // 1's = '-', 0's = '.'
    putchar( ' ' ); // space between characters
}

int main() {
    char str[] = "Stuff happens";

    puts( str );
    for( int i = 0; str[ i ]; i++ )
        morsify( str[ i ] );
    putchar( '\n' );

    char str1[] = "SOS sos SOS";

    puts( str1 );
    for( i = 0; str1[ i ]; i++ )
        morsify( str1[ i ] );
    putchar( '\n' );

    return (0);
}
Stuff happens
... ---. ..-.- .-- .--  ..--  --- --- ...- --.- ...
SOS sos SOS
... --- ...  ... --- ...  ... --- ...

If you want to "buffer-up" the characters, simply replace the putchar() with your buffering scheme. Then you could output one long string instead of each individual dot/dash & SP.

Related