Reputation: 4203
This seems like it should be really simple, but for some reason, I'm not getting it to work. I have a string called seq, which looks like this:
ala
ile
val
I want to take the first 3 characters and copy them into a different string. I use the command:
memcpy(fileName, seq, 3 * sizeof(char));
That should make fileName = "ala"
, right? But for some reason, I get fileName = "ala9"
. I'm currently working around it by just saying fileName[4] = '\0'
, but was wondering why I'm getting that 9.
Note: After changing seq to
ala
ile
val
ser
and rerunning the same code, fileName becomes "alaK"
. Not 9 anymore, but still an erroneous character.
Upvotes: 6
Views: 22666
Reputation: 126203
sprintf is your friend for extracting characters from the middle of one string and putting them in a character buffer with null termination.
sprintf(fileName, "%.3s", seq);
or
sprintf(fileName, "%.*s", 3, seq);
or even
snprintf(fileName, sizeof(fileName), "%.*s", len, seq);
will give you what you want. The *
version allows a variable length, and snprintf
is safer for avoiding buffer overflows
Upvotes: 11
Reputation: 7676
In addition to null-terminating your string,
fileName[3] = '\0';
You may also want to consider using strncpy
instead of memcpy
. Also, sizeof(char)
should always evaluate to 1, so it is redundant.
Good luck!
Upvotes: 2
Reputation: 43817
C uses a null terminator to denote the end of a string. memcpy doesn't know that you're copying strings (it just copies bytes) so it doesn't think to put one on. The workaround you have is actually the right answer.
Edit: wolfPack88 has a good point. You really need to be changing filename[3]. Also, the below comments bring up some great points about strncpy which is a choice worth learning too.
Upvotes: 18
Reputation: 490108
You should be using filename[3]='\0';
. As to why it's necessary: because nothing else has set the NUL terminator for the string, so you have to.
Edit: of course for real use, you don't use a constant like I've shown above. Typically you'd use something like:
char *substring(char *out, char const *in, size_t len) {
memcpy(out, in, len);
out[len] = '\0';
return out;
}
Note that you did have pretty much the right idea using memcpy
though. strncpy
(for an obvious example) is not really the right thing to use for this (or almost any other) purpose. On the list of standard library functions to avoid, strncpy
comes second on the list, behind only gets
(though, in fairness I have to point out that strtok
is a close third).
Also note that (like most standard library functions) this makes no attempt at verifying the parameters you pass -- for example, if you tell it to copy 99 characters from a string that's only 10 characters long into a buffer that's only 5 characters long, it'll try to copy 99 characters anyway, producing undefined behavior).
Edit2: One alternative is to use sprintf.
Upvotes: 5
Reputation: 320421
The standard library of C language has no dedicated function for copying part of a string. The proper way to do it is to use memcpy
(as you did already) and the explicitly null-terminate the result. You forgot to terminate the result, which is why you see the strange extra characters after the copied portion of the string.
Note that memcpy
will only work if you know the length of the source string in advance, i.e. you know that the copied portion of the string lies entirely inside the source string. If there's a chance that the copied portion of the source contains the terminating null-character (i.e. source string ends in the middle of the copied portion), then you'd have to either write your own function for copying or use the non-standard but widely available strlcpy
.
Sometimes you can come across code samples that attempt to use strncpy
function for that purpose. While it might appear to "work" in some cases, there's absolutely no point in using strncpy
, taking into account that it is not intended to be used that way.
Upvotes: 4
Reputation: 39208
The unexpected character is an artifact of not properly null-terminating fileName
.
In this case, fileName
must be a char
buffer having length at least 4 (three for the three characters ala and one for the terminating null character). To set the null character, you can use:
fileName[3] = '\0';
after the memcpy
.
Upvotes: 2
Reputation: 96
If you want to use memcpy to copy strings, you must set the character '\0' manually after the last character of the string. If you don't want to handle '\0' manually, use strcpy or strncpy instead.
Upvotes: 5
Reputation: 700262
Strings in C are nul terminated, meaning that you need the nul character at the end of the string. It seems like you were lucky enough to have a nul character just at the next character so that you only got one extra garbage character, you could just as well have gotten thousands of garbage characters...
Upvotes: 3
Reputation: 5113
The reason is that you copy the three character bytes from the seq, however, there is no terminating null-char. So you're workaround is not a workaround but a correct solution.
C-Strings should be null-terminated. If they're not, then the "user" of the strings reads until he cannot read any further, which results in undefined behaviour.
Btw, why not use strncpy ?
Upvotes: 2
Reputation: 14326
You need to set
fileName[3] = 0;
Make sure fileName has enough space for the end of string NUL byte.
Upvotes: 5