Filling is done to align certain types of data, that is, to ensure that data of a certain type has an address that is a multiple of some specified number. This varies depending on different CPU models, but often 2-byte integers are aligned at addresses that are multiplexes of 2 and 4-byte integers to addresses that are a multiple of 4. characters usually don't need to be aligned.
So, if there is only one field in the structure, then as long as the structure is located at the address with the corresponding border, there is no need to fill out. And it will always be: the system always aligns the blocks with the largest boundary that will ever be needed, usually 4 bytes or 8 bytes. One thing in the structure will be on the right border. The problem arises only if there are several fields, since the length of one field may not lead to the fact that the next field will be at the corresponding boundary. So, in your example, you have a char, which, of course, takes 1 byte, and an int, which takes 4. Suppose that the structure is located at 0x1000. Then, without padding, char will be placed at 0x1000, and int at 0x1001. But ints are more efficient when on 4-byte boundaries, so the compiler adds some pad bytes to push it to the next such border, 0x1004. So now you have char (1 byte), padding (3 bytes), int (4 bytes), a total of 8 bytes.
In this case, you can do nothing to improve the situation. Each structure will be aligned with a 4- or 8-byte boundary, so when the minimum is 5 bytes, in practice it will always be rounded to 8. (Sizeof will not display the indent between structures, only inside, but memory is still lost.)
In other cases, you can minimize the number of extra bytes of an element by reordering the order of the fields. For example, you had three char and three int. If you declare the structure as
struct {char a; int b; char c; int d; char e; int f;}
then the compiler will add 3 bytes after the first char to align the first int, and then three more bytes after the second char to align the second int. (1) + pad (3) + int (4) + char (1) + pad (3) + int () 4) = 24.
But if you stated this:
struct {char a; char c; char e; int b; int d; int f;}
then you get char (1) + char (1) + char (1) + pad (1) + int (4) + int (4) + int (4) = 16.
A few years ago I read a tip to always add the largest elements to minimize padding, i.e. first set longs, then ints, then shorts, then chars.
If you allocate thousands or millions, you can save a lot of memory by this technique. If you are going to select only one or two, it will not make much difference.