birderic
birderic

Reputation: 3765

strncopy copying more than n characters

I'm given a shell of a program and have to fill in a few functions.

I have two structs I am given that are automatically created and passed to the functions I must define.

typedef struct {
    char data[20];
} msg;

typedef struct {
     int seqnum;
     int acknum;
     int checksum;
     char payload[20];
 } pkt;

Say I have to define this function foo and have created it as such:

void foo(msg message) {
    printf("%s\n", message.data);
}

When that function is called, it prints out ddddddddddddddddddddôÑ@<úHn½*Ìå«*¤ú¤F«*. Unless I am incorrect, shouldn't it only be able to hold 20 characters? I am not actually creating msg.

It gets even stranger if I copy msg.data to pkt.payload.

void foo(msg message) {
    pkt packet;
    strncpy(packet.payload, message.data, sizeof(packet.payload));
    printf("%s\n", message.data);
    printf("%s\n", packet.payload);
}

message.data prints out the same as before, but packet.payload prints out eeeeeeeeeeeeeeeeeeee<úeeeeeeeeeeeeeeeeeeee²+!@<úHn½*Ìå«*¤ú¤F«*. Why is it more than 20 characters?

This is my first time using C so forgive me if this is obvious but I can't even get to the core of the assignment since I'm having trouble with the language.

Upvotes: 1

Views: 2345

Answers (3)

Etienne de Martel
Etienne de Martel

Reputation: 36995

printf(), with a %s specifier, assumes you are sending it a zero-terminated string. So it reads bytes in memory until it finds a zero (or '\0').

strncpy does not append a zero to your destination string unless a zero is encountered in the source string before n characters are reached (at which point the rest of the destination string is padded with zeros, which of course causes it to be zero-terminated).

Upvotes: 2

Svisstack
Svisstack

Reputation: 16656

strncpy(packet.payload, message.data, sizeof(packet.payload));
packet.payload[sizeof(packet.payload) - 1] = 0;

Upvotes: 0

Alex B
Alex B

Reputation: 84962

strncpy does not terminate the string being copied.

You either have to manually terminate the field,

strncpy(packet.payload, message.data, sizeof(packet.payload) - 1);
packet.payload[sizeof(packet.payload) - 1] = '\0';
printf("%s\n", message.data);
printf("%s\n", packet.payload);

or treat it as a fixed-size potentially unterminated string:

strncpy(packet.payload, message.data, sizeof(packet.payload));
printf("%s\n", message.data);
printf("%.*s\n", sizeof packet.payload, packet.payload);

Alternatively, you may keep it terminated with snprintf (C99), which is less error-prone, as it always terminates the string.

snprintf(packet.payload, sizeof packet.payload, "%s", message.data);
printf("%s\n", message.data);
printf("%s\n", packet.payload);

Upvotes: 2

Related Questions