I know this code is sloppy, I'm trying to relearn string manipulation in C. If I have a string ABBCCCD and I want to store the separate letters in a struct, is there an efficient way to do so? I have some code down below to demonstrate the long way of what I'm trying to do. (Also, do I have to manually add the null-terminator when I'm doing a strncpy?)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct dst_struct {
char a[2];
char b[3];
char c[4];
char d[2];
} dst_struct_t;
int main(void) {
char* test = "ABBCCCD";
char* src = malloc(strlen(test)+1);
strncpy(src, test, strlen(test)+1);
printf("%s\n", src);
dst_struct_t dst;
strncpy(dst.a, src, 1);
strncpy(dst.b, src+1, 2);
strncpy(dst.c, src+3, 3);
strncpy(dst.d, src+6, 1);
printf("dst.a: %s\n", dst.a);
printf("dst.b: %s\n", dst.b);
printf("dst.c: %s\n", dst.c);
printf("dst.d: %s\n", dst.d);
free(src);
}
There isn't really any better way to do this, except that you don't need to copy test to src first.
You also need to add the null terminators to all the strings. It would probably be best to write a function that does both steps: strncpy() and adding the null terminator.
function copy_n(char *dest, char *src, size_t offset, size_t len) {
strncpy(src+offset, dest, len);
dest[len] = '\0';
}
int main(void) {
char* test = "ABBCCCD";
copy_n(dst.a, test, 0, 1);
copy_n(dst.b, test, 1, 2);
copy_n(dst.c, test, 3, 3);
copy_n(dst.d, test, 6, 1);
printf("dst.a: %s\n", dst.a);
printf("dst.b: %s\n", dst.b);
printf("dst.c: %s\n", dst.c);
printf("dst.d: %s\n", dst.d);
}
From the strcpy/strncpy man page:
char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);
The strcpy() function copies the string pointed to by src, including the terminating null byte ('\0'), to the buffer pointed to by dest. The strings may not overlap, and the destination string dest must be large enough to receive the copy. Beware of buffer overruns! (See BUGS.)
The strncpy() function is similar, except that at most n bytes of src are copied. Warning: If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated.
The n argument of strncpy is generally meant to be the length of the destination buffer, as the point of the function is to be like strcpy but prevent overflowing the destination buffer if the source string is too long or not NULL-terminated. If used in that manner, your destination string will be NULL-terminated if the source string fits that length, otherwise the final byte of the buffer will contain the nth character of the source string.
However, the way you seem to be using strncpy is to set the exact number of characters you want to copy from the source buffer to place in the destination buffer. That is not really the intended purpose of strncpy. Instead, what you'd want to use is memcpy, since you are really not concerned with the zero-termination of the source string, but rather just copying a set number of characters from a set location. And yes, you will have to manually add the null-terminator if you use memcpy.
Related
I have the following code in C now
int length = 50
char *target_str = (char*) malloc(length);
char *source_str = read_string_from_somewhere() // read a string from somewhere
// with length, say 20
memcpy(target_str, source_str, length);
The scenario is that target_str is initialized with 50 bytes. source_str is a string of length 20.
If I want to copy the source_str to target_str i use memcpy() as above with length 50, which is the size of target_str. The reason I use length in memcpy is that, the source_str can have a max value of length but is usually less than that (in the above example its 20).
Now, if I want to copy till length of source_str based on its terminating character ('\0'), even if memcpy length is more than the index of terminating character, is the above code a right way to do it? or is there an alternative suggestion.
Thanks for any help.
The scenario is that target_str is initialized with 50 bytes. source_str is a string of length 20.
If I want to copy the source_str to target_str i use memcpy() as above with length 50, which is the size of target_str.
currently you ask for memcpy to read 30 characters after the end of the source string because it does not care of a possible null terminator on the source, this is an undefined behavior
because you copy a string you can use strcpy rather than memcpy
but the problem of size can be reversed, I mean the target can be smaller than the source, and without protection you will have again a undefined behavior
so you can use strncpy giving the length of the target, just take care of the necessity to add a final null character in case the target is smaller than the source :
int length = 50
char *target_str = (char*) malloc(length);
char *source_str = read_string_from_somewhere(); // length unknown
strncpy(target_str, source_str, length - 1); // -1 to let place for \0
target_str[length - 1] = 0; // force the presence of a null character at end in case
If I want to copy the source_str to target_str i use memcpy() as above
with length 50, which is the size of target_str. The reason I use
length in memcpy is that, the source_str can have a max value of
length but is usually less than that (in the above example its 20).
It is crucially important to distinguish between
the size of the array to which source_str points, and
the length of the string, if any, to which source_str points (+/- the terminator).
If source_str is certain to point to an array of length 50 or more then the memcpy() approach you present is ok. If not, then it produces undefined behavior when source_str in fact points to a shorter array. Any result within the power of your C implementation may occur.
If source_str is certain to point to a (properly-terminated) C string of no more than length - 1 characters, and if it is its string value that you want to copy, then strcpy() is more natural than memcpy(). It will copy all the string contents, up to and including the terminator. This presents no problem when source_str points to an array shorter than length, so long as it contains a string terminator.
If neither of those cases is certain to hold, then it's not clear what you want to do. The strncpy() function may cover some of those cases, but it does not cover all of them.
Now, if I want to copy till length of source_str based on its terminating character ('\0'), even if memcpy length is more than the index of terminating character, is the above code a right way to do it?
No; you'd be copying the entire content of source_str, even past the null-terminator if it occurs before the end of the allocated space for the string it is pointing to.
If your concern is minimizing the auxiliary space used by your program, what you could do is use strlen to determine the length of source_str, and allocate target_str based on that. Also, strcpy is similar to memcpy but is specifically intended for null-terminated strings (observe that it has no "size" or "length" parameter):
char *target_str = NULL;
char *source_str = read_string_from_somewhere();
size_t len = strlen(source_str);
target_str = malloc(len + 1);
strcpy(target_str, source_str);
// ...
free(target_str);
target_str = NULL;
memcpy is used to copy fixed blocks of memory, so if you want to copy something shorter that is terminated by '\n' you don't want to use memcpy.
There is other functions like strncpy or strlcpy that do similar things.
Best to check what the implementations do. I removed the optimized versions from the original source code for the sake of readability.
This is an example memcpy implementation: https://git.musl-libc.org/cgit/musl/tree/src/string/memcpy.c
void *memcpy(void *restrict dest, const void *restrict src, size_t n)
{
unsigned char *d = dest;
const unsigned char *s = src;
for (; n; n--) *d++ = *s++;
return dest;
}
It's clear that here, both pieces of memory are visited for n times. regardless of the size of source or destination string, which causes copying of memory past your string if it was shorter. Which is bad and can cause various unwanted behavior.
this is strlcpy from: https://git.musl-libc.org/cgit/musl/tree/src/string/strlcpy.c
size_t strlcpy(char *d, const char *s, size_t n)
{
char *d0 = d;
size_t *wd;
if (!n--) goto finish;
for (; n && (*d=*s); n--, s++, d++);
*d = 0;
finish:
return d-d0 + strlen(s);
}
The trick here is that n && (*d = 0) evaluates to false and will break the looping condition and exit early.
Hence this gives you the wanted behaviour.
Use strlen to determine the exact size of source_string and allocate accordingly, remembering to add an extra byte for the null terminator. Here's a full example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char *source_str = "string_read_from_somewhere";
int len = strlen(source_str);
char *target_str = malloc(len + 1);
if (!target_str) {
fprintf(stderr, "%s:%d: malloc failed", __FILE__, __LINE__);
return 1;
}
memcpy(target_str, source_str, len + 1);
puts(target_str);
free(target_str);
return 0;
}
Also, there's no need to cast the result of malloc. Don't forget to free the allocated memory.
As mentioned in the comments, you probably want to restrict the size of the malloced string to a sensible amount.
I have for instance a string. And I only want to change the beginning few characters of the string and leave the rest as they are. What is the best way to do this in C?
#include <stdio.h>
#include <string.h>
int main() {
char src[40];
char src2[40];
char dest[12];
memset(dest, '\0', sizeof(dest));
strcpy(src, "This is a string");
strcpy(src2, "That");
strncpy(dest, src, sizeof(src));
strncpy(dest, src2, sizeof(src2));
printf("Final copied string : %s\n", dest);
}
I would like the string to be changed from "This is a string" to "That is a string".
Is there an easy way to accomplish this that I am missing?
There are a few issues here.
First, dest is only 12 bytes long, which is too short to hold "This is a string". Trying to copy that string into dest will overrun the buffer. This invokes undefined behavior. Make it at least 20 bytes.
Second sizeof(src) gives you the size of the whole array, which is 40, not the length of the string. This will also give undefined behavior if the destination buffer is not big enough. Use strlen instead. The same goes for sizeof(src2).
With those changes, you should have this:
#include <stdio.h>
#include <string.h>
int main() {
char src[40];
char src2[40];
char dest[20];
memset(dest, '\0', sizeof(dest));
strcpy(src, "This is a string");
strcpy(src2, "That");
strncpy(dest, src, strlen(src));
strncpy(dest, src2, strlen(src2));
printf("Final copied string : %s\n", dest);
}
sizeof(src2) is 40 (it's the size of the entire array) - you probably meant strlen(src2) (which is just the amount of characters used for the string) :
strncpy(dest, src2, strlen(src2));
Note btw that your code has a buffer overrun issue : The dest array is not big enough to hold the resulting string. It needs to be at least 17 characters large to accomodate the "This is a string" string. You'll also want to use :
strncpy(dest, src, strlen(src));
I am confused and a little concerned about the memset() call. The memset call allows the use of strncpy() without worrying about the terminating '\0'. Such a call assumes that this logic will be used in a general purpose function that will be called from a higher level function.
If that is not the case, then the first strncpy() should be replaced with a strcpy and the memset should be abandoned:
#include <stdio.h>
#include <string.h>
int main() {
char src[40];
char src2[40];
char dest[20];
/* memset(dest, '\0', sizeof(dest)); -- No need for this */
strcpy(src, "This is a string");
strcpy(src2, "That");
strcpy(dest, src, strlen(src)); /* strcpy will put a '\0' at the end */
strncpy(dest, src2, strlen(src2));
printf("Final copied string : %s\n", dest);
}
However, if this will be called from a higher level function, then we really need to check for the lengths of the incoming strings and/or malloc the dest buffer and free it. The memset() is the elephant in the room that suggests that there is more logic to come which should be considered. Otherwise, just replace the first strncpy() with a strcpy().
Expanding on the answer by #dbush:
I think the code is still quite fragile.
#include <stdio.h>
#include <string.h>
int main() {
char src[40];
char src2[40];
char dest[20];
Here the first pitfall is created: dest is smaller than both sources. While that can be handled, it requires much more diligence in the subsequent code. It would be better to make the destination always large enough to hold the source(s).
memset(dest, '\0', sizeof(dest)); //Good
But it is also a good idea to initialize the other arrays with 0 as well.
memset(src, '\0', sizeof(src));
memset(src2, '\0', sizeof(src2));
Side note: Of course you could save the trouble of memset by just using the array initialization syntax:
char src[40] = {0};
char src2[40] = {0};
char dest[20] = {0};
The two next lines are potentially dangerous, provided that IRL the two strings might not be string constants. (And even then!) No length checking is provided... Better:
// strcpy(src, "This is a string");
// strcpy(src2, "That");
strncpy(src, "This is a string", sizeof(src)- 1);
strncpy(src2, "That", sizeof(src2) -1);
That way we make sure we don't cause any overflow.
We also make sure that the strings in src and src2 are properly null-terminated.
Now, the copying of src/src2 to dest is also dangerous. We must ensure not to overflow dest.
//strncpy(dest, src, strlen(src));
//strncpy(dest, src2, strlen(src2));
Better:
strncpy(dest, src, sizeof(dest) - 1);
strncpy(dest, "That is a long rubbish string that easily could overflow dest", sizeof(dest) -1);
We only copy as much as dest can hold and preserve the null terminator.
Now to the replacement of the first X characters. Again, we must make sure no overflow occurs. We use strlen to determine the actual size of the null-terminated string in src2, but need to use/evaluate the maximum size of dest. Therefore the mixture of strlen and sizeof.
memcpy just for the fun of it. You could use strncpy just as well.
memcpy(dest, src2, strlen(src2) < sizeof(dest) ? strlen(src2) : sizeof(dest));
printf("Final copied string : %s\n", dest);
}
So the whole, secure implementation looks like this:
#include <stdio.h>
#include <string.h>
int main() {
char src[40] = {0};
char src2[40] = {0};
char dest[20] = {0};
strncpy(src, "This is a string", sizeof(src)- 1);
strncpy(src2, "That is a long rubbish string and sooooooooooooooooooooooooo much more", sizeof(src2) -1);
strncpy(dest, src, sizeof(dest) - 1);
memcpy(dest, src2, strlen(src2) < sizeof(dest) ? strlen(src2) : sizeof(dest));
printf("Final copied string : %s\n", dest);
}
Please note that the use of sizeof is only seemingly equivalent to strlen; on char types that works, on other types you need to do more.
I have a char array in C
#define BUFSIZE 2048
unsigned char buf[BUFSIZE];
char request[10];
strcat(request "GET key01");
request[10] = '\0';
buf = request;
The request is coming from a the network with a client-server socket simulation, but I did not include that here to keep it simple.
Anyways, I have to tokenize the buf string, but also keep an untokenized copy. I tried this:
char* buf_for_token = buf;
printf("What is the buf before tokenization? %s\n", buf);
const char s[2] = " ";
char *token;
token = strtok(buf_for_token, s);
token = strtok(NULL, s);
printf("What is the buf after tokenization? %s\n", buf);
My output is:
What is the buf before tokenization? GET key01
What is the buf after tokenization? GET
I would instead like:
What is the buf before tokenization? GET key01
What is the buf after tokenization? GET key01
How can I get the value of a string from a char array and save a copy that I can manipulate without affecting the original value?
You can use the C <string.h> function:
strcpy(const char *dest, const char *src);
Which will copy from src until '\0' char, into dest, and include the '\0' char.
OR
use:
strcat(const char *dest, const char *src);
Which will append to the end of the already existent string, starting at null terminate '\0' of dest, adding all chars until and including '\0'.
OR
use:
strncpy(const char *dest, const char *src, int size);
Which wil copy n chars from char *src into char *dest.
strtok is destructive; it will modify the contents of your buffer as you tokenize it by overwriting the delimiters with a zero byte. If you need to preserve the original buffer contents, then you will either need to copy to another buffer and tokenize that second buffer, or you will need to use something besides strtok (which is often the right answer anyway).
Look at functions like strchr or strpbrk. You'll need to figure out how to extract and save the individual tokens to another buffer, but that's not that hard.
I have an exercise where I need to write a wrapper function for strcat. After it prints the string length (for debugging) it seg faults and I am not quite sure why. Any help would be greatly appreciated.
EDIT: I didn't specify that the wrapper function is supposed to guarantee that it never goes outside of the bounds of memory allocated for destination. This is why I allocated only enough memory for "string" in destination and reallocating more in the Strcat() wrapper.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* Strcat(char* destination, const char* source);
int main(void)
{
(void)printf("This strcat cannot fail!\n");
char* destination = (char*)malloc(sizeof(char)*7);
destination = "string";
(void)printf("%s\n", destination);
Strcat(destination, " concatination");
(void)printf("%s\n", destination);
(void)printf("It works!\n");
free(destination);
return 0;
}
char* Strcat(char* destination, const char* source)
{
(void)printf("%d\n", (strlen(destination)+strlen(source))*sizeof(char));
if((sizeof((strlen(destination)+strlen(source)))+1) > sizeof(destination))
destination = (char*)realloc(destination, sizeof((strlen(destination)+strlen(source)))+1);
return strcat(destination, source);
}
This line:
destination = "string";
overwrites the pointer returned from malloc(3) so you lose that memory forever. You probably meant to copy that string, so use strcpy(3) or something.
if((sizeof((strlen(destination)+strlen(source)))+1) > sizeof(destination))
That's wrong, sizeof doesn't give you anything comparable to the length of the string. Don't use it here.
Moreover, you can't really get the number of allocated bytes of the string. So if you know destination has been allocated with malloc[*], you should realloc unconditionally:
destination = (char*)realloc(destination, strlen(destination)+strlen(source)+1);
Again, no sizeof. And be prepared to handle allocation failures, which means saving the old value of destination and freeing it when realloc returns 0.
[*] Note that destination = "string" breaks this premise.
Try summat like
char *Strcat(char *d, const char *s) /* please put in the proper names - i am being lazy*
{
int dLen = strlen(d); /* ditto above */
int sLen = strlen(s);
d = (char *)realloc(d, dLen + sLen +1);
return strcat(d, s);
}
I have a string:
char * someString;
If I want the first five letters of this string and want to set it to otherString, how would I do it?
#include <string.h>
...
char otherString[6]; // note 6, not 5, there's one there for the null terminator
...
strncpy(otherString, someString, 5);
otherString[5] = '\0'; // place the null terminator
Generalized:
char* subString (const char* input, int offset, int len, char* dest)
{
int input_len = strlen (input);
if (offset + len > input_len)
{
return NULL;
}
strncpy (dest, input + offset, len);
return dest;
}
char dest[80];
const char* source = "hello world";
if (subString (source, 0, 5, dest))
{
printf ("%s\n", dest);
}
char* someString = "abcdedgh";
char* otherString = 0;
otherString = (char*)malloc(5+1);
memcpy(otherString,someString,5);
otherString[5] = 0;
UPDATE:
Tip: A good way to understand definitions is called the right-left rule (some links at the end):
Start reading from identifier and say aloud => "someString is..."
Now go to right of someString (statement has ended with a semicolon, nothing to say).
Now go left of identifier (* is encountered) => so say "...a pointer to...".
Now go to left of "*" (the keyword char is found) => say "..char".
Done!
So char* someString; => "someString is a pointer to char".
Since a pointer simply points to a certain memory address, it can also be used as the "starting point" for an "array" of characters.
That works with anything .. give it a go:
char* s[2]; //=> s is an array of two pointers to char
char** someThing; //=> someThing is a pointer to a pointer to char.
//Note: We look in the brackets first, and then move outward
char (* s)[2]; //=> s is a pointer to an array of two char
Some links:
How to interpret complex C/C++ declarations and
How To Read C Declarations
You'll need to allocate memory for the new string otherString. In general for a substring of length n, something like this may work for you (don't forget to do bounds checking...)
char *subString(char *someString, int n)
{
char *new = malloc(sizeof(char)*n+1);
strncpy(new, someString, n);
new[n] = '\0';
return new;
}
This will return a substring of the first n characters of someString. Make sure you free the memory when you are done with it using free().
You can use snprintf to get a substring of a char array with precision:
#include <stdio.h>
int main()
{
const char source[] = "This is a string array";
char dest[17];
// get first 16 characters using precision
snprintf(dest, sizeof(dest), "%.16s", source);
// print substring
puts(dest);
} // end main
Output:
This is a string
Note:
For further information see printf man page.
You can treat C strings like pointers. So when you declare:
char str[10];
str can be used as a pointer. So if you want to copy just a portion of the string you can use:
char str1[24] = "This is a simple string.";
char str2[6];
strncpy(str1 + 10, str2,6);
This will copy 6 characters from the str1 array into str2 starting at the 11th element.
I had not seen this post until now, the present collection of answers form an orgy of bad advise and compiler errors, only a few recommending memcpy are correct. Basically the answer to the question is:
someString = allocated_memory; // statically or dynamically
memcpy(someString, otherString, 5);
someString[5] = '\0';
This assuming that we know that otherString is at least 5 characters long, then this is the correct answer, period. memcpy is faster and safer than strncpy and there is no confusion about whether memcpy null terminates the string or not - it doesn't, so we definitely have to append the null termination manually.
The main problem here is that strncpy is a very dangerous function that should not be used for any purpose. The function was never intended to be used for null terminated strings and it's presence in the C standard is a mistake. See Is strcpy dangerous and what should be used instead?, I will quote some relevant parts from that post for convenience:
Somewhere at the time when Microsoft flagged strcpy as obsolete and dangerous, some other misguided rumour started. This nasty rumour said that strncpy should be used as a safer version of strcpy. Since it takes the size as parameter and it's already part of the C standard lib, so it's portable. This seemed very convenient - spread the word, forget about non-standard strcpy_s, lets use strncpy! No, this is not a good idea...
Looking at the history of strncpy, it goes back to the very earliest days of Unix, where several string formats co-existed. Something called "fixed width strings" existed - they were not null terminated but came with a fixed size stored together with the string. One of the things Dennis Ritchie (the inventor of the C language) wished to avoid when creating C, was to store the size together with arrays [The Development of the C Language, Dennis M. Ritchie]. Likely in the same spirit as this, the "fixed width strings" were getting phased out over time, in favour for null terminated ones.
The function used to copy these old fixed width strings was named strncpy. This is the sole purpose that it was created for. It has no relation to strcpy. In particular it was never intended to be some more secure version - computer program security wasn't even invented when these functions were made.
Somehow strncpy still made it into the first C standard in 1989. A whole lot of highly questionable functions did - the reason was always backwards compatibility. We can also read the story about strncpy in the C99 rationale 7.21.2.4:
The strncpy function
strncpy was initially introduced into the C library to deal with fixed-length name fields in
structures such as directory entries. Such fields are not used in the same way as strings: the
trailing null is unnecessary for a maximum-length field, and setting trailing bytes for shorter
5 names to null assures efficient field-wise comparisons. strncpy is not by origin a “bounded
strcpy,” and the Committee preferred to recognize existing practice rather than alter the function
to better suit it to such use.
The Codidact link also contains some examples showing how strncpy will fail to terminate a copied string.
I think it's easy way... but I don't know how I can pass the result variable directly then I create a local char array as temp and return it.
char* substr(char *buff, uint8_t start,uint8_t len, char* substr)
{
strncpy(substr, buff+start, len);
substr[len] = 0;
return substr;
}
strncpy(otherString, someString, 5);
Don't forget to allocate memory for otherString.
#include <stdio.h>
#include <string.h>
int main ()
{
char someString[]="abcdedgh";
char otherString[]="00000";
memcpy (otherString, someString, 5);
printf ("someString: %s\notherString: %s\n", someString, otherString);
return 0;
}
You will not need stdio.h if you don't use the printf statement and putting constants in all but the smallest programs is bad form and should be avoided.
Doing it all in two fell swoops:
char *otherString = strncpy((char*)malloc(6), someString);
otherString[5] = 0;
char largeSrt[] = "123456789-123"; // original string
char * substr;
substr = strchr(largeSrt, '-'); // we save the new string "-123"
int substringLength = strlen(largeSrt) - strlen(substr); // 13-4=9 (bigger string size) - (new string size)
char *newStr = malloc(sizeof(char) * substringLength + 1);// keep memory free to new string
strncpy(newStr, largeSrt, substringLength); // copy only 9 characters
newStr[substringLength] = '\0'; // close the new string with final character
printf("newStr=%s\n", newStr);
free(newStr); // you free the memory
Try this code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char* substr(const char *src, unsigned int start, unsigned int end);
int main(void)
{
char *text = "The test string is here";
char *subtext = substr(text,9,14);
printf("The original string is: %s\n",text);
printf("Substring is: %s",subtext);
return 0;
}
char* substr(const char *src, unsigned int start, unsigned int end)
{
unsigned int subtext_len = end-start+2;
char *subtext = malloc(sizeof(char)*subtext_len);
strncpy(subtext,&src[start],subtext_len-1);
subtext[subtext_len-1] = '\0';
return subtext;
}