wolfPack88
wolfPack88

Reputation: 4203

Copying part of a string in C

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

Answers (10)

Chris Dodd
Chris Dodd

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

Parappa
Parappa

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

Pace
Pace

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

Jerry Coffin
Jerry Coffin

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

AnT stands with Russia
AnT stands with Russia

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

Daniel Trebbien
Daniel Trebbien

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

gclello
gclello

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

Guffa
Guffa

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

Henri
Henri

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

florin
florin

Reputation: 14326

You need to set

fileName[3] = 0;

Make sure fileName has enough space for the end of string NUL byte.

Upvotes: 5

Related Questions