Here is my code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char f[] = "First";
char s[] = "Second";
char *tmp = malloc(strlen(f) + strlen(s) + 2);
strcpy(tmp, f);
strcpy(tmp, s);
printf("%s", tmp);
free(tmp);
return 0;
}
I'm trying to concatenate f and s. The problem is that tmp contains only "Second" as a array.
What I miss here
strcpy copies the string to the beginning of the destination, you want strcat instead.
The second strcpy overwrites the previous one. Both copy its content to the tmp pointer (at the start of it). You should use tmp+strlen(f).
Or even better use strcat.
And even better use more secure methods like: strncpy, strncat, etc..
If you insist on using strcpy, your code should be slightly modified:
int main() {
const char *f = "First";
const char *s = "Second";
char *tmp = malloc(strlen(f) + strlen(s) + 1);
strcpy(tmp, f);
strcpy(tmp+strlen(f), s);
printf("%s", tmp);
free(tmp);
return 0;
}
You should consider using strncpy instead of strcpy for safety reasons. Also, strcat is a more conventional function for concatenating C string.
EDIT Here is an example of using strncpy instead of strcpy
#define MAX 1024
int main() {
const char *f = "First";
const char *s = "Second";
size_t len_f = min(strlen(f), MAX);
size_t len_s = min(strlen(s), MAX);
size_t len_total = len_f + len_s;
char *tmp = malloc(len_total + 1);
strncpy(tmp, f, len_f);
strncpy(tmp+len_f, s, len_s);
tmp[len_total] = '\0';
printf("%s", tmp);
free(tmp);
return 0;
}
You may want to use strcat instead of your second strcpy call, like this:
strcpy(tmp, f);
strcat(tmp, s);
Note also that allocating strlen(f) + strlen(s) + 1 bytes for tmp is sufficient no need to allocate strlen(f) + strlen(s) + 2 bytes. After concatenation, you'll get only one string, so only one null character is required.
using strcat() instead, which means append a string accroding to the MSDN doc.strcpy() just means copy a string. If you don't want to use strcat(), you should point out the position by using strncpy() or strcpy_s(). Please refer to the document.
The problem is that you copy the second string in place of the first one (the first parameter of strcpy() is where to copy the string) and this effectively overwrites the first string. Here's an idea of what you need:
size_t firstLen = strlen( f );
size_t secondLen = strlen( s );
char *tmp = malloc(firstLen + secondLen + 1);
strcpy(tmp, f);
strcpy(tmp + firstLen, s);
This can be achieved by using strcat(), although that would lead to an extra scan along the copied string.
Here is the correct idiomatic safe way to do what you want:
size_t l = strlen(f);
char *tmp = malloc(l + strlen(s) + 1);
strcpy(tmp, f);
strcpy(tmp+l, s);
or:
size_t l = strlen(f) + strlen(s) + 1;
char *tmp = malloc(l);
snprintf(tmp, l, "%s%s", f, s);
I tend to prefer the latter unless you're writing embedded systems code where you want to avoid pulling in printf dependency.
Finally, note that you should be testing malloc for failure, and that it's useless and harmful to allocate memory and copy the strings if all you want to do is print them - you could just do the following:
printf("%s%s", f, s);
Related
I need to read a file and look for a word and replace with a new word but it's not working as it should:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
FILE * f = fopen("text" , "rb" );
if(f == NULL ){
perror("error ");
return 1;
}
char chain[100];
while(!feof(f)){
fgets(chain, 100 , f);
}
printf("%s", chain);
fclose(f);
printf("\n \n ;D \n");
return 0;
}
And this is how I replace the old word:
char str[] ="This is a hiall samplesss friends string";
char * pch;
pch = strstr (str,"hiall");
strncpy (pch,"sam",5);
puts (str);
thanks
That strncpy is copying 5 chars from "sam" into pch. Note however that "sam" has only 3 characters, so it is copying the three characters plus the \0 terminator. That's why it is "deleting" the rest of the string: it is adding a terminator right after "sam", so you are getting This is a sam in the output.
If you strncpy only 3 characters, you'll get this:
This is a samll samplesss friends string
If what you want is something like find-and-replace (i.e. replacing "hiall" with "sam" and getting This is a sam samplesss friends string), you need to move the rest of the string backwards. A simple strncpy won't work because the destination memory overlaps with the target. For this, you can either use memmove, or use an auxiliary buffer:
char str[] = "This is a hiall samplesss friends string";
char* pch;
char* old_word = "hiall";
char* new_word = "sam";
size_t len_old = strlen(old_word);
size_t len_new = strlen(new_word);
pch = strstr(str, old_word);
assert(len_new <= len_old);
if (pch) {
char* rest = pch + len_old;
size_t len_rest = strlen(rest);
char* aux = malloc(len_rest + 1);
strncpy(aux, rest, len_rest + 1);
strncpy(pch, new_word, len_new);
strncpy(pch + len_new, aux, len_rest + 1);
free(aux);
puts(str);
}
Note that this will only work if new_word is the same size or shorter than old_word. If new_word is longer, you won't be able to edit in-place (in the string str itself), unless the original string has extra memory for it (e.g. if you declared it with str[1000] to guarantee you can increase its size enough — then the code above would work). The safest approach if you can't plan ahead what size new_word is going to be would be to allocate a new string:
char str[] ="This is a hiall samplesss friends string";
char* pch;
char* old_word = "hiall";
char* new_word = "sam";
pch = strstr(str, old_word);
size_t len_str = strlen(str);
size_t len_new = strlen(new_word);
size_t len_old = strlen(old_word);
if (pch) {
char* new_str = malloc(len_str - len_old + len_new + 1);
ptrdiff_t pos_word = pch - str;
strncpy(new_str, str, pos_word);
strncpy(new_str + pos_word, new_word, len_new);
strncpy(new_str + pos_word + len_new, pch + len_old,
len_str - pos_word - len_old + 1);
puts(new_str);
}
(Edit: addressed issues pointed out by David Bowling in the comments.)
I'm doing a client-server project in linux and I need to concatenate some strings.
I tried my code on visual studio in windows and it works fine, but it linux it gives me some garbage. I've got this function:
char* concat(char s1[], char s2[])
{
int tam = 0;
tam = strlen(s1);
tam += strlen(s2);
char *resultado = malloc(sizeof(char) * tam) ;
strcpy(resultado, s1);
strcat(resultado, s2);
return resultado;
}
I read that the problem is the missing of '\0' and I've done that:
char* concat(char s1[], char s2[])
{
int tam = 0;
tam = strlen(s1);
tam += strlen(s2);
char *resultado = malloc(sizeof(char) * tam) ;
resultado[tam+1] = '\0';
strcpy(resultado, s1);
strcat(resultado, s2);
return resultado;
}
The first 4 times that I called the function it works (the garbage disappeared), but then it gives me `malloc(): memory corruption
Anyone can help me?
You are not allocating space for the nul terminator, a very common mistake.
Suggestions:
Don't use sizeof(char) it's 1 by definition.
Check that malloc() did not return NULL.
Always remember the nul byte.
So your code would be fixed like this
char *resultado = malloc(1 + tam);
if (resultado == NULL)
pleaseDoNotUse_resultado();
Also, notice that this line
resultado[tam + 1] = '\0';
has multiple issues
tam + 1 us outside the allocated block.
You don't need to do that, strcpy() will do it for you.
Using strcat() and strcpy() in this situation is inefficient, because you already know how many bytes to copy, this
char *concat(char *s1, char *s2)
{
size_t l1;
size_t l2;
char *resultado
if ((s1 == NULL) || (s2 == NULL))
return NULL;
l1 = strlen(s1);
l2 = strlen(s2);
resultado = malloc(1 + l1 + l2) ;
if (resultado == NULL)
return NULL;
memcpy(resultado , s1, l1);
memcpy(resultado + l1, s2, l2);
resultado[l1 + l2] = '\0';
return resultado;
}
would be more efficient, even when you are checking for NULL like a paranoic freak, it would be faster than strcpy() and strcat(), because you will only compute the lengths once.
You're not allocating memory to hold the termianting null. Remember, strlen() does not count the null-terminator while calculating the string length. Nevertheless, you need that space in the destination buffer to put the null terminator.
You should write
char *resultado = malloc(tam + 1) ;
Also,
resultado[tam+1] = '\0';
is very wrong, because, array indexing is 0 based in C and here, you're overrunning the allocated memory (yes, even while allocating a size of tam+1 also) which will invoke undefined behaviour. You don't need that at all, you can get rid of that.
After that, as a side-note, as mentioned by Iharob also,
Check for the success of malloc() before using the returned pointer.
In C standard, sizeof(char) is guranteed to be 1. No need of using it while calculating the size for malloc().
You should allocate one byte more than the resulting string's length:
char *resultado = malloc(tam + 1) ;
Functions strcpy and strcat take care about the terminating NUL, you don't have to add it manually.
There are a lot of find/replace functions available on the internet, but i can't find why this is not working...( my own solution )
Here is what i tried
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* strrpl(char *str, char* find, char *replace)
{
int i;
char *pt = strstr(str, find), *firstStr;
firstStr = (char* )malloc(100 * sizeof(char));
// copy just until i find what i need to replace
// i tried to specify the length of firstStr just with pt - str
strncpy(firstStr, str, strlen(str) - strlen(pt));
strcat(firstStr, replace);
strcat(firstStr, pt + strlen(find));
for(i = 0; i < strlen(firstStr); i++)
str[i] = firstStr[i];
return str;
}
int main()
{
char *s, *s1, *s2;
s = (char* )malloc(100 * sizeof(char));
s1 = (char* )malloc(100 * sizeof(char));
s2 = (char* )malloc(100 * sizeof(char));
scanf("%s", s1);
scanf("%s", s2);
scanf("%s", s);
printf("%s", strrpl(s, s1, s2));
return 0;
}
The compilation gives me the error "segmentation fault" but i can't figure what memmory is he trying to alloc and he can't. I overrided a memory block or something? Please help :)
Thanks
I overrided a memory block or something?
You have:
A potential buffer overflow when you allocate firstStr. Who says the result will be less than 100 characters?
Another potential buffer overflow when you copy the answer back to the input string. Who says it will fit?
A potential buffer overflow each time you use scanf.
A memory leak each time you call malloc.
An inefficient implementation of strcpy just before return str;.
A crash (formally, undefined behaviour) when the input string does not contain the replacement string. strstr returns NULL when there is no match and you never check for it.
A potential issue with strncpy which leaves your string not NUL-terminated if there's not enough space for NUL.
Here is the immediate problem: when strstr returns NULL, your code does not pay attention. Add this line:
char *pt = strstr(str, find), *firstStr;
if (!pt) return str;
Another problem is that the call of strncpy is incorrect:
strncpy(firstStr, str, strlen(str) - strlen(pt));
it will leave firstStr unterminated, because str is longer than the substring being copied. The subsequent call
strcat(firstStr, replace);
will operate on a string that is not null-terminated, causing undefined behavior.
"Shotgun" approach to fixing it would be to use calloc instead of malloc to put zeros into firstStr. A more precise approach would be placing '\0' at the end of the copied substring.
With these fixes in place, your code runs OK (demo). However, there are several issues that need to be addressed:
You do not free any of the resources that you allocate dynamically - this results in memory leaks.
You do not compute how much memory to allocate - If a 5-character string is replaced for a 100-character string in a 100-character string, you overrun the temporary buffer.
You are using strncpy incorrectly - the function is intended for fixed-length strings. Use memcpy instead.
You are using strcat instead of memcpy or strcpy - this is inefficient.
You have not checked for the return value of strstr.
Try the below code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* strrpl(char *str, char* find, char *replace)
{
int i;
char *pt = strstr(str, find);
char *firstStr;
if(pt == NULL){
printf("cannot find string \n");
return NULL;
}
firstStr = (char* )malloc(100 * sizeof(char));
// copy just until i find what i need to replace
// i tried to specify the length of firstStr just with pt - str
strncpy(firstStr, str, strlen(str) - strlen(pt));
strcat(firstStr, replace);
strcat(firstStr, pt + strlen(find));
for(i = 0; i < strlen(firstStr); i++)
str[i] = firstStr[i];
return str;
}
int main()
{
char *s, *s1, *s2, *s3;
s = (char* )malloc(100 * sizeof(char));
s1 = (char* )malloc(100 * sizeof(char));
s2 = (char* )malloc(100 * sizeof(char));
s3 = (char* )malloc(100 * sizeof(char));
scanf("%s", s);//input string
scanf("%s", s1);//string to find
scanf("%s", s2);//string to replace
s3 = strrpl(s, s1, s2);
if(s3 != NULL)
printf("%s \n",s3);
return 0;
}
I'm struggling with memory allocation. I wanted to input a string into another and I made two functions that stop working at the same place - realloc. These functions are very similar. In first one I copy char by char into a temporary string and when I try to copy temporary string to the first one is the place where I get errors. In the second function I copy the end of first string (from the given position) to a temporary string, reallocate the first string (this is where I get errors) and remove everything in i from the given position. Then I append second string and temporary to a first string. Here is my code.
First function:
// str2 - is a string that I want to input in first string(str)
// at certain position (pos)
void ins (char **str, char *str2, int pos)
{
// lenght of first and second strings
int len = strlen(str[0]),
len2 = strlen(str2),
i, j, l = 0;
// creating temporary string
char *s = (char *) malloc ((len + len2) * sizeof(char));
// copying first part of first string
for (i = 0; i < pos; i++)
s[i] = str[0][i];
// copying second string
for (j = 0; j < len2; j++)
s[i + j] = str2[j];
// copying second part of first string
for (int k = pos; k < len; k++)
{
s[i + j + l] = str[0][k];
l++;
}
// reallocating additional space for second string
// and copying temporary string to first string
str[0] = (char *) realloc (str[0], (len + len2) * sizeof(char));
strcpy(str[0], s);
free(s);
s = NULL;
}
Second function:
void ins2 (char **str,char *str2, int pos)
{
// lenght of first and second string
int len = strlen(str[0]),
len2 = strlen(str2);
// creating a temporary string and copying
// from the given position
char *s = (char *) malloc ((len - pos) * sizeof(char));
strcpy(s, str[0] + pos);
// reallocating space for string that will be added
// deleting part of it from the given position
str[0] = (char *) realloc(str[0], (len + len2) * sizeof(char));
str[0][pos] = '\0';
// adding second string and temporary string
strcat(str[0], str2);
strcat(str[0], s);
// be free, temporary string
free(s);
s = NULL;
}
If you're doing what I think you're trying to do, you need one realloc() for this, assuming the incoming string is indeed already dynamically allocated (it better be):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void ins (char **str, const char *str2, size_t pos)
{
// lenght of first and second strings
size_t len = strlen(*str);
size_t len2 = strlen(str2);
// reallocate new string
char *tmp = realloc(*str, len + len2 + 1);
if (tmp != NULL)
{
*str = tmp;
memmove(tmp+pos+len2, tmp+pos, len-pos);
memcpy(tmp+pos, str2, len2);
tmp[len+len2] = 0;
}
}
int main()
{
char *str = strdup("A simple string");
char s2[] = "inserted ";
printf("%s\n", str);
ins(&str, s2, 9);
printf("%s\n", str);
free(str);
return 0;
}
Output
A simple string
A simple inserted string
How It Works
The passed-in strings are both sent through strlen() to obtain their lengths. Once we have those we know how large the resulting buffer needs to be.
Once we realloc() the buffer, the original content is preserved, but we need to (possibly) shift content of the first string to open a hole for the second string. That shift, if done, may require overlapped memory be moved (as it does in the sample). For such memory copying, memmove() is used. Unlike memcpy(), the memmove() library function supports copying where the source and destination regions may overlap.
Once the hole is made, we memcpy() the second string into position. There is no need for strcpy() since we already know the length.
We finish by tacking the last slot to a terminating 0, thereby finishing the null-terminated string and completing the operation
Note I made no affordances at all for this regarding someone passing an invalid pos (out of range), NULL strings, optimizing to nothing if str2 is empty (or NULL), etc. That cleanup I leave to you, but I hope the idea of how this can be done is clear.
gcc 4.4.3
c89
I have the following string
sip:12387654345443222118765#xxx.xxx.xxx.xxx
How can I extract just the number? I just want the number.
12387654345443222118765
Many thanks for any advice,
There are lots of ways to do it, if the string is well-formatted you could use strchr() to search for the : and use strchr() again to search for the # and take everything in between.
Here is another method that looks for a continuous sequence of digits:
char *start = sipStr + strcspn(sipStr, "0123456789");
int len = strspn(start, "0123456789");
char *copy = malloc(len + 1);
memcpy(copy, start, len);
copy[len] = '\0'; //add null terminator
...
//don't forget to
free(copy);
It sounds like you want it as a numeric type, which is going to be difficult (it's too large to fit in an int or a long). In theory you could just do:
const char* original = "sip:12387654345443222118765#xxx.xxx.xxx.xxx";
long num = strtoul(original + 4, NULL, 10);
but it will overflow and strtoul will return -1. If you want it as a string and you know it's always going to be that exact length, you can just pull out the substring with strcpy/strncpy:
const char* original = "sip:12387654345443222118765#xxx.xxx.xxx.xxx";
char num[24];
strncpy(num, original + 4, 23);
num[23] = 0;
If you don't know it's going to be 23 characters long every time, you'll need to find the # sign in the original string first:
unsigned int num_length = strchr(original, '#') - (original + 4);
char* num = malloc(num_length + 1);
strncpy(num, original + 4, num_length);
num[num_length] = 0;
Use a regular expression :)
#include <regex.h>
regcomp() // compile your regex
regexec() // run your regex
regfree() // free your regex
:)
Have a look into the strtok or strtok_r functions.
Here is something that will deal with a variable width substring, which doesn't care about the starting position of the substring. For instance, if string was iax2:xxx#xx.xx.xx.xx, it would still work. It will, however return NULL if either delimiter can't be found.
It uses strchr() to find the delimiters, which lets us know where to start copying and where to stop. It returns an allocated string, the calling function must free() the returned pointer.
I'm pretty sure this is what you want?
Note: Edited from original to be more re-usable and a bit saner.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *extract_string(const char *str, const char s1, const char s2)
{
char *ret = NULL, *pos1 = NULL, *pos2 = NULL;
size_t len;
if (str == NULL || s1 < 0 || s2 < 0)
return NULL;
pos1 = strchr(str, s1);
pos2 = strchr(str, s2);
if (! pos1 || ! pos2)
return NULL;
len = ((pos2 - str) - (pos1 - str) - 1);
ret = (char *) malloc(len + 1);
if (ret == NULL)
return NULL;
memcpy(ret, str + (pos1 - str) + 1, len);
ret[len] = '\0';
return ret;
}
int main(void)
{
const char *string = "sip:12387654345443222118765#xxx.xxx.xxx.xxx";
char *buff = NULL;
buff = extract_string(string, ':', '#');
if (buff == NULL)
return 1;
printf("The string extracted from %s is %s\n" , string, buff);
free(buff);
return 0;
}
You could easily modify that to not care if the second delimiter is not found and just copy everything to the right of the first. That's an exercise for the reader.