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.
Related
I have a dynamically allocated char array, I want to combine two strings into it, so I tried the following:
char *strcpy2 (char *str1, char *str2)
{
int total = strlen (str1) + strlen (str2) + 1;
char *nstr = malloc (sizeof (char) * total);
while (*str1 != '\0') *nstr++ = *str1++;
while (*str2 != '\0') *nstr++ = *str2++;
*nstr = '\0';
printf ("size: %d\n", strlen (nstr));
return &(nstr[0]);
}
int main (void)
{
char *concat = strcpy2 ("Hello, ", "World.");
puts (concat);
free (concat);
return 0;
}
When I ran it, it printed the size of nstr is 0 and then Segmentation fault (core dumped).
However when I did this:
char *strcpy2 (char *str1, char *str2)
{
int total = strlen (str1) + strlen (str2) + 1;
char *nstr = malloc (sizeof (char) * total);
char *p = nstr;
while (*str1 != '\0') *p++ = *str1++;
while (*str2 != '\0') *p++ = *str2++;
*p = 0;
printf ("size: %d\n", strlen (nstr));
return nstr;
}
It worked fine and printed the correct length of nstr. I'm puzzled, what caused the crash?
You need to return the value of nstr that was originally returned by malloc().
Your first code block increments nstr until it points to the end of the allocated memory. The code then attempts to use and free that address, which is not owned by your program.
You need to save the starting address of the string so you can return it.
In your first case, you increment the nstr constantly, and in the end, you use
printf ("size: %d\n", strlen (nstr));
where nstr points to the final location after all the increment (containing null).Results in 0 length. Then, you return the incremented pointer to the caller and try to free() it. Results in Undefined Behavior.
OTOH, in the second case, you have the pointer to the primarily allocated memory intact, through which you count the string length, returns correct value and later, free()-ing is also proper, so that works as expected.
In the first function, you're returning the wrong pointer. It's pointing at the null terminator of the string, so the length is zero. When you try to free() it, it isn't a pointer you got from malloc(). Undefined behavior results.
You're incrementing the nstr pointer when copying the two strings, and that's the pointer you're using to represent the string itself. Simply copy it in another variable and use it when referring to the string:
char *strcpy2 (char *str1, char *str2)
{
int total = strlen (str1) + strlen (str2) + 1;
char *nstr = malloc (sizeof (char) * total);
char *str = nstr; // the string
while (*str1 != '\0') *nstr++ = *str1++;
while (*str2 != '\0') *nstr++ = *str2++;
*nstr = '\0';
printf ("size: %d\n", strlen (str)); // used here
return str; // and here
}
You can see it in action here: https://ideone.com/ncpVMU
I also took the liberty of fixing your goofy return statement:
return &(nstr[0]);
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.
I am writing a C program in Unix and cannot figure out how to set an array element to NULL. I need to be able to do this to remove multiple characters from a string.
You can't assign null to specific char array index as value represented by that index is char instead of pointer. But if you need to remove specific character from given string, you can implement this as follows
void removeChar(char *str, char garbage) {
char *src, *dst;
for (src = dst = str; *src != '\0'; src++) {
*dst = *src;
if (*dst != garbage) dst++;
}
*dst = '\0';
}
Test Program
#include<stdio.h>
int main(void) {
char* str = malloc(strlen("abcdef")+1);
strcpy(str, "abcdbbbef");
removeChar(str, 'b');
printf("%s", str);
free(str);
return 0;
}
output
acdef
If you have a char[], you can zero-out individual elements using this:
char arr[10] = "foo";
arr[1] = '\0';
Note that this isn't the same as assigning NULL, since arr[1] is a char and not a pointer, you can't assign NULL to it.
That said, that probably won't do what you think it will. The above example will produce the string f, not fo as you seem to expect.
If you want to remove characters from a string, you have to shift the contents of the string to the left (including the null terminator) using memmove and some pointer arithmetic:
Example:
#include <stdio.h>
#include <string.h>
int removechars(char *str, size_t pos, size_t cnt) {
size_t len = strlen(str);
if (pos + cnt > len)
return -1;
memmove(str + pos, str + pos + cnt, len - pos - cnt + 1);
return 0;
}
Then use it like so:
char str[12] = "hello world";
if (removechars(str, 5, 4) == 0) /* remove 4 chars starting at str[5] */
printf("%s\n", str); /* hellold */
If you're talking about an array of pointers (say char **), you'd just say array[element] = NULL;. But it sounds as though you really want to just truncate a string (char *), in which case you'd actually want to write string[index] = '\0', where \0 is the null byte. But, as far as I know, 0, '\0', and NULL are all equivalent and equal to 0 (please correct me if I'm wrong). Of course, for clarity, you should use 0 for numbers, '\0' for chars and strings, and NULL for pointers.
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);