How to use strdup and strcat in C [duplicate] - c

Say I wanted to duplicate a string then concatenate a value to it.
Using stl std::string, it's:
string s = "hello" ;
string s2 = s + " there" ; // effectively dup/cat
in C:
char* s = "hello" ;
char* s2 = strdup( s ) ;
strcat( s2, " there" ) ; // s2 is too short for this operation
The only way I know to do this in C is:
char* s = "hello" ;
char* s2=(char*)malloc( strlen(s) + strlen( " there" ) + 1 ) ; // allocate enough space
strcpy( s2, s ) ;
strcat( s2, " there" ) ;
Is there a more elegant way to do this in C?

You could make one:
char* strcat_copy(const char *str1, const char *str2) {
int str1_len, str2_len;
char *new_str;
/* null check */
str1_len = strlen(str1);
str2_len = strlen(str2);
new_str = malloc(str1_len + str2_len + 1);
/* null check */
memcpy(new_str, str1, str1_len);
memcpy(new_str + str1_len, str2, str2_len + 1);
return new_str;
}

A GNU extension is asprintf() that allocates the required buffer:
char* s2;
if (-1 != asprintf(&s2, "%s%s", "hello", "there")
{
free(s2);
}

Not really. C simply doesn't have a good string management framework like C++ does. Using malloc(), strcpy() and strcat() like you have shown is about as close as you can get to what you are asking for.

You could use a library like GLib and then use its string type:
GString * g_string_append (GString *string, const gchar *val);
Adds a string onto the end of a GString, expanding it if necessary.

Inspired by nightcracker, I also thought of
// writes s1 and s2 into a new string and returns it
char* catcpy( char* s1, char* s2 )
{
char* res = (char*)malloc( strlen(s1)+strlen(s2)+1 ) ;
// A:
sprintf( res, "%s%s", s1, s2 ) ;
return res ;
// OR B:
*res=0 ; // write the null terminator first
strcat( res, s1 ) ;
strcat( res, s2 ) ;
return res ;
}

Related

C-string alternatives to strtok_r() and strsep() that don't modify the original string pointer?

I was taking a look at the 2 C-string functions, strtok_r() and strsep(), and noticed both
functions modify the location of the original string passed in.
Are there any other C-string functions that don't modify the original string passed in?
In my application, the original string is dynamically allocated, so I wish to free the original
string after the parsing is done.
An example with strtok_r()
int main(){
char * str = strdup("Tutorial and example");
char* token;
char* rest = str;
printf("%s\n", rest);
while ((token = strtok_r(rest, " ", &rest)))
printf("%s\n", token);
printf("\n%s\n",str);
return(0);
}
Output
Tutorial and example
Tutorial
and
example
Tutorial
In the very last line, I wish for str to point to the unmodified cstring "Tutorial and example".
A similar output would have occured with strsep() as well.
int main(){
char * str = strdup("Tutorial and example");
char* token;
char* rest = str;
printf("%s\n", rest);
while ((token = strsep(&rest, " ")))
printf("%s\n", token);
if (rest != NULL)
printf("%s\n", rest);
printf("%s\n", str);
return(0);
}
Thank you.
I think you are misunderstanding strtok_r. It does not change the location of the original string, moreover, it can not - the function can not change the value of the pointer passed into it and make this change visible to the calling code.
What it can and will do is modifying the contents of the string itself, by replacing tokens with nul-terminators. So to answer your original question:
In my application, the original string is dynamically allocated, so I
wish to free the original string after the parsing is done.
You do not have to do anything special. You can and should free original string after you are done with it.
You are seeing a single word Tutorial printed simply because the next character was replaced with nul-terminator and printf stop there. If you are to inspect the string character by character, you will see that it otherwise have remained intact.
Though the mentioned string functions change the original string nevertheless the pointer str points to the dynamically allocated memory and you may use it to free the allocated memory.
if you do not want to change the original string you can use standard C string functions strspn and strcspn.
For example
#include <stdio.h>
#include <string.h>
int main(void)
{
const char *s = "Tutorial and example";
const char *separator = " \t";
puts( s );
for ( const char *p = s; *p; )
{
p += strspn( p, separator );
const char *prev = p;
p += strcspn( p, separator );
int width = p - prev;
if ( width ) printf( "%.*s\n", width, prev );
}
return 0;
}
The program output is
Tutorial and example
Tutorial
and
example
Using this approach you can dynamically allocate memory for each extracted substring.
For example
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
const char *s = "Tutorial and example";
const char *separator = " \t";
puts( s );
size_t n = 0;
char **a = NULL;
int success = 1;
for ( const char *p = s; success && *p; )
{
p += strspn( p, separator );
const char *prev = p;
p += strcspn( p, separator );
if ( p - prev != 0 )
{
char *t = malloc( p - prev + 1 );
if ( ( success = t != NULL ) )
{
t[p - prev] = '\0';
memcpy( t, prev, p - prev );
char **tmp = realloc( a, ( n + 1 ) * sizeof( char * ) );
if ( ( success = tmp != NULL ) )
{
a = tmp;
a[n++] = t;
}
else
{
free( t );
}
}
}
}
for ( size_t i = 0; i < n; i++)
{
puts( a[i] );
}
for ( size_t i = 0; i < n; i++)
{
free( a[i] );
}
free( a );
return 0;
}
The program output is the same as shown above.
Tutorial and example
Tutorial
and
example

Is there a C function for inserting/appending char* to an defined location in another char*?

I want to insert a char* to a defined location in another char*. For example:
char str1[80] = "Hello world!";
char str2[] = "the ";
I want the result to be Hello the world! (insert str2 to location 6 of str1)
I have tried:
#include <stdio.h>
char str1[80] = "Hello world!";
char str2[] = "the ";
char tmp1[80];
char tmp2[80];
char *string_insert(char *scr, char *ins, int loc){
// Get the chars from location 0 -> loc
for(int i = 0; i <= loc; i++){
tmp1[i] = scr[i];
}
// Get the chars from loc -> end of the string
for(int i = 0; i < sizeof(scr) - loc; i++){
tmp2[i] = scr[i + loc];
}
// Insert the string ins
for(int i = 0; i < sizeof(ins); i++){
tmp1[i + loc] = ins[i];
}
// Add the rest of the original string
for(int i = 0; i < sizeof(scr) - loc; i++){
tmp1[loc + 1 + i] = tmp2[i];
}
return tmp1;
}
int main(){
printf("%s", string_insert(str1, str2, 6));
return 0;
}
But then I got Hello two. You can execute it online at onlinegdb.com
I also wonder if there is any function from string.h that can do this?
Thanks for any help!
There's no function in the standard library to insert a string into another.
You have to first create enough space for the characters you want to insert by
moving the original characters to the right:
Hello World\0
Hello WorlWorld\0 <- move characters to the right
Hello the World\0 <- rewrite (including ' ')
In your example you have enough space (you create a buffer of 80 characters and use only 12 of them) but you should be absolutely be sure that this is the case.
However this is not what your code does. You copy those characters in another buffer and use that one as return value. In other words, your str1 is left unchanged. I don't think this is what you wanted, right?
fixed code with some comments to help with understanding:
#include <stdio.h>
#include <string.h>
char str1[] = "Hello world!"; // use `[]` to include trailing \0
char str2[] = "the ";
char tmp1[80]; // not very good idea to use global variables, but for algorithm learning purposes it is ok
char tmp2[80];
char *string_insert(char *src, char *str, int loc){
// function uses global variable tmp1
// if total length of string is > 80 - result is undefined
int ti = 0; // index in tmp variable
while (ti<loc) tmp1[ti++] = *src++; // copy first part from src
while (*str) tmp1[ti++] = *str++; // append str
while (*src) tmp1[ti++] = *src++; // append the rest of src
tmp1[ti] = 0; // don't forget trailing 0
return tmp1;
}
int main(){
printf("%s", string_insert(str1, str2, 6));
return 0;
}
There is no string insert function. There is a strcat() function which appends. Implementing your own however is simple enough using the string primitives that are available:
char* string_insert( char* scr, const char* ins, size_t loc )
{
size_t ins_len = strlen(ins) ;
strcpy( &scr[loc + ins_len], &scr[loc] ) ;
memcpy( &scr[loc], ins, ins_len ) ;
return scr ;
}
Here the end of the string is moved to make space for ins, then ins copied to the gap.
Example usage:
int main()
{
char str1[80] = "Hello world!" ;
const char* str2 = "the " ;
printf( "%s\n", string_insert( str1, str2, 6 ) ) ;
return 0;
}
The insertion is done in place and directly modifies scr so needs no destination buffer. That would be the idiomatic behaviour given the interface the you have specified. The use of the global tmp1 and tmp2 arrays in your attempt are not good practice, and entirely unnecessary (as is always the case with globals). If you do want to modify a separate destination string (so scr is const), then you should pass that buffer as an argument:
char* string_insert( const char* scr, const char* ins, size_t loc, char* dest )
{
size_t ins_len = strlen(ins) ;
memmove( dest, scr, loc ) ;
strcpy( &dest[loc + ins_len], &scr[loc] ) ;
memcpy( &dest[loc], ins, ins_len ) ;
return dest ;
}
int main()
{
const char* str1 = "Hello world!";
const char* str2 = "the " ;
char str3[80] = "" ;
printf( "%s\n", string_insert(str1, str2, 6, str3 ) ) ;
return 0;
}
The use of const parameters allows string literals to be passed as arguments so for the first "in-place" version.:
char str[80] = "Hello world!" ;
printf( "%s\n", string_insert( str, "the ", 6 ) ) ;
And for the "destination buffer" version:
char str[80] = "" ;
printf( "%s\n", string_insert( "Hello world!", "the ", 6, str ) ) ;

Dynamic string concatenation with strcat in C

I have experienced an issue while using strcat, using realloc however, strcat overwrites destination string
char *splitStr(char *line) {
char *str_;
str_ = (char *) malloc(1);
char *ptr = strtok(line,"\n");
int a;
while (ptr != NULL) {
if (ptr[0] != '$') {
printf("oncesi %s\n", str_);
a = strlen(ptr) + strlen(str_) + 1;
str_ = realloc(str_, a);
strcat(str_, ptr);
str_[a] = '\0';
printf("sontasi:%s\n", str_);
}
ptr = strtok(NULL, "\n");
}
printf("splitStr %d\n", strlen(str_));
printf("%s", str_);
return str_;
}
and my input value is ;
*4
$3
200
$4
4814
$7
SUCCESS
$4
3204
so I want to split this input value via strtok;
strtok(line,'\n');
and concat all line without start "$" char to new char. However, this code give following output;
line: *4
oncesi
sontasi:*4
oncesi *4
200tasi:*4
200esi *4
4814asi:*4
4814si *4
SUCCESS:*4
SUCCESS*4
3204ESS:*4
splitStr 25
seems to overwrite source string.
do you have any idea why this issue could be happening ?
the following proposed code:
cleanly compiles
performs the indicated functionality
is slightly reformated for readability of output
checks for errors from malloc() and realloc()
shows how to initialize the str[] array, which is the problem in the OPs posted code.
the function: strlen() returns a size_t, not an int. so the proper output format conversion specifier is: %zu
does not use trailing underscores on variable names
and now, the proposed code:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
char *splitStr( char *line )
{
printf("original line: %s\n", line);
char *str = malloc(1);
if( !str )
{
perror( "malloc failed" );
exit( EXIT_FAILURE );
}
str[0] = '\0'; // critical statement
char *token = strtok(line,"\n");
while( token )
{
if( token[0] != '$')
{
char* temp = realloc( str, strlen( token ) + strlen( str ) + 1 );
if( ! temp )
{
perror( "realloc failed" );
free( str );
exit( EXIT_FAILURE );
}
str = temp; // update pointer
strcat(str, token);
printf( "concat result: %s\n", str );
}
token = strtok(NULL, "\n");
}
printf("splitStr %zu\n", strlen(str));
return str;
}
int main( void )
{
char firstStr[] = "$abcd\n$defg\nhijk\n";
char *firstNewStr = splitStr( firstStr );
printf( "returned: %s\n\n\n\n", firstNewStr );
free( firstNewStr );
char secondStr[] = "abcd\ndefg\nhijk\n";
char *secondNewStr = splitStr( secondStr );
printf( "returned: %s\n\n\n\n", secondNewStr );
free( secondNewStr );
}
a run of the proposed code results in:
original line: $abcd
$defg
hijk
concat result: hijk
splitStr 4
returned: hijk
original line: abcd
defg
hijk
concat result: abcd
concat result: abcddefg
concat result: abcddefghijk
splitStr 12
returned: abcddefghijk
Your input contains Windows/DOS end-of-line codings "\r\n".
Since strtok() just replaces '\n' with '\0', the '\r' stays in the string. On output it moves the cursor to the left and additional characters overwrite old characters, at least visually.
Your concatenated string should be OK, however. Count the characters, and don't forget to include a '\r' for each line: "*4\r200\r4814\rSUCCESS\r3204\r" are 25 characters as the output splitStr 25 shows.
Additional notes:
As others already said, str_ = (char *) malloc(1); does not initialize the space str_ points to. You need to do this yourself, in example by str_[0] = '\0';.
Don't use underscores that way.
You don't need to cast the result of malloc(), it is a void* that is compatible to char* (and any other).

Replace a string within a C char string (strreplace, no sprintf)

Hello and sorry if this questions is already answered (in the way I want to :-) ) but I think I have a memory problem.
Assuming the following C function (yes, this one is very dirty and not optimized):
char *strreplace(char **str, char *dst, char *replace) {
int replacestart = stringcompare(*str, dst), replaceend = strlen(dst), replacelen = strlen(replace);
char *tmp1 = (char *)malloc(sizeof(char) * (replacestart + 1)), *tmp2 = (char *)malloc(sizeof(char) * ((strlen(*str) - replaceend) + 1));
memset(tmp1, 0, sizeof(char) * (replacestart + 1));
memset(tmp2, 0, sizeof(char) * ((strlen(*str) - replaceend) + 1));
strncpy(tmp1, *str, replacestart);
strncpy(tmp2, *str + replacestart + replaceend, (strlen(*str) - (replaceend + replacestart)));
*str = realloc(*str, strlen(tmp1) + replacelen + strlen(tmp2));
memset(*str, 0, strlen(tmp1) + replacelen + strlen(tmp2));
strncpy(*str, tmp1, strlen(tmp1));
strncpy(*str + strlen(tmp1), replace, replacelen);
strncpy(*str + strlen(tmp1) + replacelen, tmp2, strlen(tmp2));
return *str;
}
As seen, it should replace *dst with *replace whithin **str.
This works basically as expected. Here's the problem:
The output (*str) is not cleard out with zeros after memsetting it and has still the wrong length, even after reallocating.
Means, if the string is longer after replacing, the last chars are cutted of *str.
In turn, if the string is shorter, old chars are at the end of the char string are found.
What did I wrong. Mentioned that I don't want to use sprintf and no C++-STL, just want to do this with pointers in C.
Other words, what would be the right way to replace a string in an c char string with pointers.
Thanks alot.
EDIT after reqeuest for more information
I use this function as following:
...open a textfile via FILE type, determining file lengts (fseek)...
char *filecontent = (char *)malloc(sizeof(char) * filesize);
if(filesize != fread(filecontent, sizeof(char), filesize, fd)) {
free(filecontent);
return -1;
}
streplace(&filecontent, "[#TOBEREPLACED#]", "replaced");
...doing other stuff with filecontent...
EDIT 2, adding stringcompare()
int stringcompare(const char *string, const char *substr) {
int i, j, firstOcc;
i = 0, j = 0;
while(string[i] != '\0') {
while(string[i] != substr[0] && string[i] != '\0') {
i++;
}
if(string[i] == '\0') {
return -1;
}
firstOcc = i;
while(string[i] == substr[j] && string[i] != '\0' && substr[j] != '\0') {
i++;
j++;
}
if(substr[j] == '\0') {
return firstOcc;
}
if(string[i] == '\0') {
return -1;
}
i = firstOcc + 1;
j = 0;
}
}
The logic of the function is not simple as it seems at the first glance.
You should decide what action to execute 1) if the source string is empty and 2) if the destination string is empty.
For example if the destination string is empty then the standard function strstr will return the address of the first character of the source string. However logically if dst is an empty string then the source string should not be changed except the case when it is in turn an empty string. In this case the function should just create a new string equal to the string replace.
Take into account that as the strings dst and replace are not changed within the function they should be declared with the qualifier const.
char * strreplace( char **str, const char *dst, const char *replace );
Also the function should report whether a new memory allocation was successful within the function by returning a null pointer in case when the allocation failed.
Taking all this into account the function can look the following way as it is shown in the demonstrative program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * strreplace( char **str, const char *dst, const char *replace )
{
char *result = *str;
if ( *str[0] == '\0' )
{
if ( dst[0] == '\0' && replace[0] != '\0' )
{
char *result = malloc( strlen( replace ) + 1 );
if ( result )
{
strcpy( result, replace );
free( *str );
*str = result;
}
}
}
else if ( dst[0] != '\0' )
{
char *pos = strstr( *str, dst );
if ( pos != NULL )
{
size_t dst_n = strlen( dst );
size_t replace_n = strlen( replace );
result = ( char * )malloc( strlen( *str ) - dst_n + replace_n + 1 );
if ( result )
{
size_t n = pos - *str;
strncpy( result, *str, n );
strcpy( result + n, replace );
strcpy( result + n + replace_n, *str + n + dst_n );
}
free( *str );
*str = result;
}
}
return result;
}
int main(void)
{
const char *hello = "Hello everybody here";
char *str = malloc( sizeof( char ) );
str[0] = '\0';
if ( strreplace( &str, "", hello ) )
{
puts( str );
}
if ( strreplace( &str, "everybody", "Eurobertics" ) )
{
puts( str );
}
if ( strreplace( &str, "Hello", "Bye" ) )
{
puts( str );
}
if ( strreplace( &str, " here", "" ) )
{
puts( str );
}
if ( strreplace( &str, "Bye ", "" ) )
{
puts( str );
}
free( str );
return 0;
}
The program output is
Hello everybody here
Hello Eurobertics here
Bye Eurobertics here
Bye Eurobertics
Eurobertics
Your function looks overly complex. Here is a simple, working version:
char *strreplace(char **str, char *dst, char *replace) char *strreplace(char **str, char *dst, char *replace)
{
char *start, *tmp;
int n;
if ((start=strstr(*str,dst))==0) return(0);
n= (start-*str) + strlen(start+strlen(dst)) + strlen(replace) + 1;
tmp=malloc(n);
strncpy(tmp,*str,start-*str);
strcpy(tmp+(start-*str),replace);
strcat(tmp,start+strlen(dst));
free(*str);
*str= tmp;
return(tmp);
}
With test function:
void reptest(void)
{
char *src;
char rep[]= "brave new world";
src=malloc(strlen("Hello world of wonders")+1);
strcpy(src,"Hello world of wonders");
strreplace(&src,"world",rep);
printf("%s\n", src);
free(src);
}
Edit: my previous version forgot to copy the remainder. Fixed.

String concat in C [duplicate]

This question already has answers here:
How do I concatenate const/literal strings in C?
(17 answers)
Closed 6 years ago.
void xsdValidation(char *xsdName, char *xmlName){
char *terminalCommand;
system("xmllint --noout --schema ", xsdName , xmlName);
}
I have a little problem with that. I have a code to valide my xml. And my xml's name and xsd's name came from as a argument. How can i concat these 3 things?
Use snprintf():
/* determine buffer size */
int len = snprintf(NULL, 0, "xmllint, --noout --schema %s %s", xsdName, xmlName);
if (len < 0) {
/* error handling for EILSEQ here */
}
char *buf = malloc(len + 1);
if (buf == NULL) {
/* err handling for malloc() failure here */
}
snprintf(buf, (size_t)len, "xmllint, --noout --schema %s %s", xsdName, xmlName);
system(buf);
free(buf);
On a sufficiently recent system, you could also use asprintf() to greatly simplify this code:
char *buf = NULL;
asprintf(&buf, "xmllint, --noout --schema %s %s", xsdName, xmlName);
if (buf == NULL) {
/* error handling here */
}
system(buf);
free(buf);
Note that all these approaches fail if xsdName or xmlName contain spaces or other special characters. You might want to invoke an exec function directly to avoid that problem.
You can use strcat() to concat strings.
void xsdValidation(char *xsdName, char *xmlName){
static const char *xmlLint = "xmllint --noout --schema ";
/* do not forget to +1 for terminating null character */
char *terminalCommand = malloc(strlen(xmlLint) + strlen(xsdName) + strlen(xmlName) + 1);
if(terminalCommand != NULL){
strcpy(terminalCommand, xmlLint); /* use strcpy() here to initialize the result buffer */
strcat(terminalCommand, xsdName);
strcat(terminalCommand, xmlName);
system(terminalCommand);
free(terminalCommand);
}
}
This may improve performance a little because it reuse the calculated length.
void xsdValidation(char *xsdName, char *xmlName){
static const char *xmlLint = "xmllint --noout --schema ";
size_t xmlLintLen = strlen(xmlLint);
size_t xsdNameLen = strlen(xsdName);
size_t xmlNameLen = strlen(xmlName);
/* do not forget to +1 for terminating null character */
char *terminalCommand = malloc(xmlLintLen + xsdNameLen + xmlNameLen + 1);
if(terminalCommand != NULL){
/* use strcpy() to copy the strings */
strcpy(terminalCommand, xmlLint);
strcpy(terminalCommand + xmlLintLen, xsdName);
strcpy(terminalCommand + xmlLintLen + xsdNameLen, xmlName);
system(terminalCommand);
free(terminalCommand);
}
}
If the compiler supports variable length arrays then you may write
void xsdValidation( const char *xsdName, const char *xmlName )
{
const char *command = "xmllint --noout --schema ";
char terminalCommand[strlen( command ) + strlen( xsdName ) + strlen( xmlName ) + 2];
strcpy( terminalCommand, command );
strcat( terminalCommand, xsdName );
strcat( terminalCommand, " " );
strcat( terminalCommand, xmlName );
system( terminalCommand );
}
Otherwise you should to allocate the required array dynamically. For example
void xsdValidation( const char *xsdName, const char *xmlName )
{
const char *command = "xmllint --noout --schema ";
char *terminalCommand =
malloc( strlen( command ) + strlen( xsdName ) + strlen( xmlName ) + 2 );
if ( terminalCommand != NULL )
{
strcpy( terminalCommand, command );
strcat( terminalCommand, xsdName );
strcat( terminalCommand, " " );
strcat( terminalCommand, xmlName );
system( terminalCommand );
free( terminalCommand );
}
}

Resources