How can I efficiently split strings and copy substrings in C? - c

I have used to split C strings by many means: strstr, strsep, strtok, strtok_r...Here is a case where I have a delimiter and I want to split the string. Having only done so in languages such as Java, JavaScript, Python..it seems verbose and clumsy. It feels a bit fragile..Is there a better way to do this? I feel that I have to put a lot of trust in arithmetic.
char message [] = "apples are better than bananas...But good as grapes?";
char *delimiter_location = strstr(message, "...");
int m1_strlen = delimiter_location - message;
int m1_chararr_size = m1_strlen + 1;
char message_1 [m1_chararr_size];
memset(message_1, '\0', m1_chararr_size);
strncpy(message_1, message, m1_strlen);
printf("message: %s\n", message);
printf("message 1: %s", message_1);

You could use a library for regular expressions, like discussed here.
Your code can be streamlined into:
char message [] = "apples are better than bananas...But good as grapes?";
char *delimiter_location = strstr(message, "...");
int m1_strlen = delimiter_location - message;
// Not every C standard and every compiler supports dynamically sized arrays.
// In those cases you need to use malloc() and free().
// Or even better: strdup() or strndup().
char message_1[m1_strlen + 1];
// NB no need to call memset() because the space is written to immediately:
strncpy(message_1, message, m1_strlen);
message_1[m1_strlen] = '\0'; // This ensures a terminated string.
printf("message: %s\n", message);
printf("message 1: %s\n", message_1);

Related

Cleaner Implementation of strtok

Just for the fun of it I am writing a program that will take a user inputted string (or maybe even a text document) and scramble the words within the string.
I am attempting to use the strtok function to separate each word in the string. At the moment I feel like my current implementation of strtok is sloppy:
int main(int argc, char *argv[])
{
char *string, *word;
if(!(string = getstr())) //function I wrote to retrieve a string
{
fputs("Error.\n", stderr);
exit(1);
}
char array[strlen(string) + 1]; //declare an array sized to the length of the string
strcpy(array, string); //copy the string into the array
free(string);
if(word = strtok(array, " "))
{
//later I'll just write each word into a matrix, not important right now.
while(word = strtok(NULL, " "))
{
//later I'll just write each word into a matrix, not important right now.
}
}
return 0;
}
I feel like there must be a cleaner way of implementing strtok without declaring an array midway through the program. It just doesn't feel correct to me. Is using strtok the correct way to go about this? I would rather not use a fixed size array, as I like everything to be dynamic, which is why I'm starting to doubt using strtok is the correct way to go.
If your string is malloced as suggested by your free. Then you don't need to copy it in a new buffer (which is btw 1 character too short). Use the buffer you were provided.
You only need to duplicate it if it was given to you by a const char * i.e. you're not allowed to modify the content of the buffer.
It's also better to use strtok_r as the regular strtokis not reentrant.
You can use scanf() instead of getstr() and strtok()
char word[100];
while(scanf(" %s",word)!=EOF) {
// use the word string here
}
the user should stop input chracters with
EOF = CTRL + D (for Linux)
EOF = CTRL + Z (for Windows)

add in a char* some other data c code

I have this part in a code:
char* data="My name is: ";
I would like to add to this the argv[1] argument with represents a name. How to do this in c code? I've tried strcpy and strcat but i have segmentation fault when Ipcp do this:
strcpy(data,argv[1]);
Can anyone please help?
Also why this: data=data+argv[1] is not working?
You need to provide some memory, where the result of the concatentation can be stored into. For example:
char buffer[1024];
strcpy(buffer, "My name is: ");
strcat(buffer, argv[1]);
Note, however, that this is error prone: if the value of argv[1] combined with the prefix string is longer than 1024 characters, this produces a buffer overflow. So, maybe something like this:
char* prefix = "My name is: ";
int length = strlen(prefix) + strlen(argv[1]) + 1;
char* buffer = malloc(length);
if (!buffer) abort();
else
{
strcpy(buffer, prefix);
strcat(buffer, argv[1]);
/* Do something with buffer here. And don't
* forget to free it, once you no longer need
* it. This is C -- no garbage collection. */
free(buffer);
}
Also why this: data=data+argv[1] is not working?
About this one - in C data and argv are nothing more than pointers to address in the memory containing your string. You can't concatenate strings(char*) this way.
I suggest to take a look at the string library and maybe a bit more in C as a whole.
Memory for data will be allocated in read-only section. so modifying will cause issue.
where in memory are string literals ? stack / heap?
+ operator will not do concat as you thought.
strcat() function is implemented in string.h.
You cant append to th data pointer because there are no space in it
char result_data [1024];
char* data="My name is: ";
strcat(result_data, data);
strcat(result_data, argv[1]);

Too much code for string concatenation in C

I get a lot of strcat lines in my code. Is there a better way to concatenate strings in C?
char material[50]; // it is defined before this code.
char result[10000];
strcpy(result, "// Assign new material to worldGlobe\n");
strcat(result, "shadingNode -asShader lambert -n ");
strcat(result, material);
strcat(result, ";\n");
You could use a format string in conjunction with snprintf() (safe compared to sprintf()):
snprintf(result, 10000,
"// Assign new material to worldGlobe\nshadingNode -asShader lambert -n %s;\n",
material);
strcat is only really suitable for really small strings; it has several problems for anything non-trivial, such as:
Due to the Schlemiel The Painter problem, strcat is O(n) over the length of the input strings, that is, the longer your strings, the longer each concatenation takes. This is because strcat has to walk the entire string to find its end. To solve this, store the length of the string along with the string data, which will allow you to jump directly to the end of the string.
It does not do any bounds checking. If you strcat too much onto the end of a string, it will happily write past the end of the string, producing a segfault in the best case, a severe security vulnerability in the worst, and most likely some bugs that will make you bash your head against the wall. strncat partially solves this problem, as long as you pass it the correct size of the destination buffer.
If your destination buffer is too small, neither strcat nor strncat will increase its size: you'll have to do this yourself.
There are two practical solutions in your situation:
a) The Tower Of Hanoi algorithm: Build a stack of strings. If a new string is shorter than the stack top, push it onto the stack. If it's longer, pop off the top, concatenate, and repeat the process with the result. When you're done pushing, concatenate what's on the stack. This is what std::stringstream in C++ or StringBuilder in .NET do, and if you look around, I'm sure you'll find a suitable implementation in C.
b) Write your strings directly to a stream. What you're outputting looks a lot like code - why not write it to a file directly?
What about
sprintf(result, "// Assign new material to worldGlobe\nshadingNode -asShader lambert -n %s;\n\0", material);
Try stpcpy; see link. Your sample code becomes:
char material[50]; // it is defined before this code.
char result[10000], *p = result;
p = stpcpy(p, "// Assign new material to worldGlobe\n");
p = stpcpy(p, "shadingNode -asShader lambert -n ");
p = stpcpy(p, material);
p = stpcpy(p, ";\n");
This function is available in Linux; the man page for stpcpy on my system states:
This function is not part of the C or POSIX.1 standards, and is not customary on Unix systems, but is not a GNU invention either. Perhaps it comes from MS-DOS.
If you don't have it, it is easy enough to write:
char *stpcpy(char *restrict dst, const char *restrict src) {
return strcpy(dst, src) + strlen(src);
}
This assumes you are aware of the dangers of strcpy.
C is mostly a do-it-yourself language.
Now that you know how to concat strings, you should write your own function to make it easier.
I'd suggest something like:
char* str_multicat(char* result, ...);
And call it something like:
str_mutlicat(result, "// Assign new material to worldGlobe\n",
"shadingNode -asShader lambert -n ",
material,
";\n",
NULL);
(hint, if you don't know the ... syntax, look into va_arg, va_start, va_end)
It would by pretty straight forward to build a string buffer struct that will keep track of the current position in your buffer, and combine that with vsprintf to get a catf(). The function vsnprintf() (assuming it's available) is just like printf, except it takes a va_list instead of ... after the format string.
This approach has the advantage over other answers that it lets you 'cat' from anywhere in your code that has access to the struct without explicitly carrying around the current length or recalculating each time it like strcat does.
Here's a rough sketch free of charge.....
/* Note: the typedef is for the pointer, not the struct. */
typedef struct StrBufStruct {
char * buffer,
size_t size,
size_t pos
} * StrBuf;
/* Create a new StrBuf. NOTE: Could statically allocate too. */
StrBuf newStrBuf(size_t size){
StrBuf sb;
sb = malloc( sizeof(struct StrBufStruct) );
sb->size = size;
sb->pos = 0;
sb->buffer = malloc( size );
/* TODO: ALWAYS CHECK YOUR MALLOC!!! */
}
int sbcatf( StrBuf b, char * fmt, ... )
{
va_list ap;
int res;
if( b->pos < b->size )
{
va_start(ap,fmt);
res = vsnprintf( b->buffer[b->pos], b->size - b->pos, fmt, ap );
b->pos += res;
va_end();
} else {
/* If you want to get really fancy, use realloc so you don't have to worry
about buffer size at all. But be careful, you can run out of memory. */
}
}
/* TODO: Write a free/delete function */
int main(int argc, char **argv){
int i;
/* initialize your structure */
StrBuf sb = newStrBuf(10000);
/* concatenate numbers 0-999 */
for(i=0; i < 1000; i++){
sbcatf(sb, "I=%d\n", i);
}
/* TODO: whatever needs to be done with sb->buffer */
/* free your structure */
deleteStrBuf(sb);
}
Also note that if all you're trying to do is make a really long string but want to be able to have line breaks in your code, this is usually acceptable, although I won't personally guarantee portability. I also use the technique to separate strings at "\n" line breaks to make the code look like the resulting string really would.
const char * someString = "this is one really really really really"
"long stttttttttrrrrrrrrrrrrrrrrrrrriiiiiiiiiiinnnnnnngggggg"
" because the compiler will automatically concatenate string"
" literals until we reach a ';' after a \" character";
You could have a function that returns a pointer to the end of the string, and use that end pointer in future calls. That'd eliminate a bunch of the extra "first, find the end of the string" stuff.
char* faster_cat(char* dest, const char* src)
{
strcpy(dest, src);
return dest + strlen(src);
}
Use like:
char result[10000];
char *end = &result[0];
result[0] = '\0'; // not strictly necessary if you cat a string, but why not
end = faster_cat(end, "// Assign new material to worldGlobe\n");
end = faster_cat(end, "shadingNode -asShader lambert -n ");
end = faster_cat(end, material);
end = faster_cat(end, ";\n");
// result now contains the whole catted string

Copying a part of a string (substring) in C

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;
}

Using strcat in C

Okay so I have the following Code which appends a string to another in C#, note that this is Just an example, so giving alternative string concatination methods in C# is not nessesary, this is just to simplify the example.
string Data = "";
Data +="\n\nHTTP/1.1 " + Status_code;
Data += "\nContent-Type: " + Content_Type;
Data += "\nServer: PT06";
Data += "\nContent-Length: " + Content_Lengt;
Data += "\nDate: " + Date;
Data += "\n" + HTML;
Now I'd like to do the exact same thing in C and I'm trying to do this the following way
time_t rawtime;
time ( &rawtime );
char *message = "\n\nHTTP/1.1 ";
message = strcat(message, Status_code);
message = strcat(message, "\nContent-Type: ");
message = strcat(message, Content_Type);
message = strcat(message, "\nServer: PT06");
message = strcat(message, "\nContent-Length: ");
message = strcat(message, Content_Lengt);
message = strcat(message, "\nDate: ");
message = strcat(message, ctime(&rawtime));
message = strcat(message, "\n");
message = strcat(message, HTML);
Now, this gives me a Segment fault, I know why, I access and read on memory that i shouldn't. But the question is, how do i solve it? Could I use string.h and just do it the same way that I did in C#?
Change
char *message = "\n\nHTTP/1.1 ";
to
char message[1024];
strcpy(message,"\n\nHTTP/1.1 ");
and you should be ok, up to a total message length of 1023.
Edit: (as per mjy's comment). Using strcat in this fashion is a great way of getting buffer overflows. You could readily write a small function that checks the size of the buffer and length of incoming string addition to overcome this, or use realloc on a dynamic buffer. IMO, the onus is on the programmer to check correct buffer sizes where they are used, as with sprintfs and other C strings functions. I assume that C is being used over C++ for performance reasons, and hence STL is not an option.
Edit: As per request from Filip's comment, a simple strcat implementation based on a fixed size char buffer:
char buffer[MAXSIZE] = "";
int mystrcat(char *addition)
{
if (strlen(buffer) + strlen(addition) + sizeof(char) >= MaxSize)
return(FAILED);
strcat(buffer,addition);
return(OK);
}
Using dynamic allocation:
char *buffer = NULL;
int mystrcat(char *addition)
{
buffer = realloc(buffer, strlen(buffer) + strlen(addition) + sizeof(char));
if (!buffer)
return(FAIL);
strcat(buffer, addition);
return(OK);
}
In this case you have to free your buffer manually when you are finished with it. (Handled by destructors in C++ equivalents)
Addendum (Pax):
Okay, since you didn't actually explain why you had to create message[1024], here it is.
With char *x = "hello", the actual bytes ('h','e','l','l','o',0) (null on the end) are stored in an area of memory separate from the variables (and quite possibly read-only) and the variable x is set to point to it. After the null, there's probably something else very important. So you can't append to that at all.
With char x[1024]; strcpy(x,"hello");, you first allocate 1K om memory which is totally dedicated to x. Then you copy "hello" into it, and still leave quite a bit of space at the end for appending more strings. You won't get into trouble until you append more than the 1K-odd allowed.
End addendum (Pax):
I wonder why no one mentioned snprintf() from stdio.h yet. That's the C way to output multiple values and you won't even have to convert your primitives to strings beforehand.
The following example uses a stack allocated fixed-sized buffer. Otherwise, you have to malloc() the buffer (and store its size), which would make it possible to realloc() on overflow...
char buffer[1024];
int len = snprintf(buffer, sizeof(buffer), "%s %i", "a string", 5);
if(len < 0 || len >= sizeof(buffer))
{
// buffer too small or error
}
Edit: You might also consider using the asprintf() function. It's a widely available GNU extension and part of TR 24731-2 (which means it might make it into the next C standard). The example from above would read
char * buffer;
if(asprintf(&buffer, "%s %i", "a string", 5) < 0)
{
// (allocation?) error
}
Remember to free() the buffer when done using it!
Start from using the safer strncat function. In general always use the safer 'n' functions that will not overflow if the size of a string is bigger than a specific size.
In C you need to take care of string sizes yourself. So you need to know how big the resulting string will be and accommodate for it. If you know the sizes of all the strings at the left side, you should create a buffer big enough to hold the resulting string.
message points to a char const[] that you can't write to, yet that's exactly where strcat is writing. You need to malloc() a sufficiently large buffer.
As said previously, you have to write to a sufficiently large buffer. Unfortunately, doing so is a lot of extra work. Most C applications that deal with strings use a dynamically resizable string buffer for doing concatenations.
glib includes an implementation of this, glib strings, which I recommend using for any application that uses strings heavily. It makes managing the memory easier, and prevents buffer overflows.
Have not seen any mention of the strlcpy, strlcat function, which is similar to the 'n' functions except also takes into account the trailing 0. Both take a third argument indicating the maximum length of the output buffer and are found in string.h.
example:
char blah[]="blah";
char buffer[1024];
strlcpy(buffer,"herro!!!",sizeof(buffer));
strlcat(buffer,blah,sizeof(buffer));
printf("%s\n",buffer);
Will output "herro!!!blah"
char blah[]="blah";
char buffer[10];
strlcpy(buffer,"herro!!!",sizeof(buffer));
strlcat(buffer,blah,sizeof(buffer));
printf("%s\n",buffer);
will output "herro!!!b" due to the limited size of buffer[], with no segfaulting. ^^
Only problem is not all platforms seem to include it in their libc (such as linux ._.), most all BSD varients DO seem to have it.
In that case, code for both functions can be found here and easily added: strlcpy, strlcat,
the rest of string.h
The safe way to do this in classic C style is:
char *strconcat(char *s1, char *s2)
{
size_t old_size;
char *t;
old_size = strlen(s1);
/* cannot use realloc() on initial const char* */
t = malloc(old_size + strlen(s2) + 1);
strcpy(t, s1);
strcpy(t + old_size, s2);
return t;
}
...
char *message = "\n\nHTTP/1.1 ";
message = strconcat (message, Status_code);
message = strconcat (message, "\nContent-Type: ");
Now you can say a lot of bad things about it: it's inefficient, it fragments your memory, it's ugly ... but it's more or less what any language with a string concatenation operator and C type (zero-terminated) strings will do (except that most of these languages will have garbage collection built-in).

Resources