I have a function append_string, which appends str2 to str1:
void append_string(char* str1, char* str2) {
int new_length = strlen(str1)+strlen(str2);
size_t new_size = sizeof(char)*(new_length);
str1 = (char*) realloc(str1, new_size);
strcat(str1, str2);
}
As shown in the function, I'm trying to increase the size using a the combined size of the strings.
Whenever I call append_str("", "adc");, I get "realloc(): Invalid pointer"
What did I do wrong?
At least these problems:
Attempting to reallocate something not allocated.
realloc(str1, new_size) attempts to reallocate the string literal "" leading to "realloc(): Invalid pointer".
Size off by 1
New size did not account for the null character.
// size_t new_size = sizeof(char)*(new_length);
size_t new_size = sizeof(char)*(new_length + 1);
Code loses the allocated pointer
Calling code lost the value of the new pointer str.
Weak type for sizing
Use size_t.
Instead, pass in an allocated pointer or NULL by its address.
void append_string(char** str, const char* appendage) {
size_t new_length = strlen(*str) + strlen(appendage);
size_t new_size = sizeof(char)*(new_length + 1);
*str = realloc(*str, new_size);
strcat(*str, appendage);
}
// Usage
char *s = malloc(1);
strcpy(s, "");
append_str(&s, "adc");
puts(s);
Advanced issues include:
What to do if realloc() returns NULL?
How to handle appendage overlapping str?
Do not use strcat(). Avoid slow code. Better to retain the original string length and copy from there.
void append_string(char** str, const char* appendage) {
size_t str_len = *str ? strlen(*str) : 0;
size_t app_len = strlen(appendage);
void *p = realloc(*str, str_len + app_len + 1);
if (p == NULL) {
// Handle Error - various approaches
free(*str);
*str = NULL;
} else {
strcpy(*str + str_len, appendage);
}
}
Still need to handle case when appendage overlaps *str.
void append_string_when_overlap_possible(char** str, const char* appendage) {
size_t str_len = *str ? strlen(*str) : 0;
size_t app_len = strlen(appendage);
char *p = malloc(str_len + app_len + 1);
if (p == NULL) {
// Handle Error - various approaches
free(*str);
*str = NULL;
} else {
if (*str) {
strcpy(p, *str);
}
strcpy(p + str_len, appendage);
free(*str);
*str = p;
}
}
Related
This is my code
char function(char *dst)
{
int i;
char *arr;
i = 0;
while(dst[i] != '\0')
{
arr[i] = dst[i];
i++;
}
dst[i] != '\0'
return(arr);
}
int main(void)
{
char a[] ="asdf"
printf("%s", function(a);
}
I want to copy *dst to empty *arr but my code didn't work.
I can't understand.
How can I copy array without inner function in C(ex_strcpy, memspy....)
Thank you
Apart from missing ; and making sure that the string being passed to the function is always a '\0' terminated one ( else the program will run into side effects strcpy causes ). and returning char* instead of char, you missed allocating memory for arr
// return char * instead of char
char* function(char *dst)
{
// Note - sizeof(dst) wont work
// Neither does sizeof(dst)/sizeof(char)
// allocate one extra for '\0'
size_t size_to_alloc = (strlen(dst) + 1) * (sizeof *arr);
char *arr = malloc( size_to_alloc );
char *p = arr;
for ( ; *dst ; p++, dst++)
*p = *dst;
*p = '\0';
return(arr);
}
If you want to dynamically copy an array, you'll need to allocate memory for the char array using malloc or other equivalent. Make sure you free the memory once you're done with it. I would suggest reading some posts on malloc and allocating memory in c.
This is probably a good place to start.
https://www.geeksforgeeks.org/dynamic-memory-allocation-in-c-using-malloc-calloc-free-and-realloc/
#include <stdio.h>
#include <stdlib.h>
char* function(char *dst, size_t length) {
int i;
// Allocating the memory needed for the char array.
char *arr = (char*) malloc (sizeof(char) * length);
i = 0;
while(dst[i] != '\0') {
arr[i] = dst[i];
i++;
}
arr[length - 1] = '\0';
return(arr);
}
int main(void) {
char a[] ="asdf";
// Getting length of the array
size_t length = sizeof(a) / sizeof(a[0]);
char* val = function(a, length);
printf("%s", val);
free(val);
}
You are missing the memory allocation and basically attempting to recode strdup. See below:
char *ft_strdup(const char *src)
{
char *dst;
int len;
len = 0;
while (src[len]) // no inner function
++len;
if (!(dst = malloc(sizeof(char) * (len + 1)))) // need 1 extra char to NULL terminate.
return NULL;
dst[len] = '\0';
while (--len > -1)
dst[len] = src[len];
return dst;
}
Note that it makes sense to code your own version of strdup and include it in your program library as this function is not part of the C Standard.
If there is a possibility of copying strings without using c functions, perhaps it can be done by doing what c functions do.
it may be interesting to see what strcpy does:
https://code.woboq.org/userspace/glibc/string/strcpy.c.html
char *
STRCPY (char *dest, const char *src)
{
return memcpy (dest, src, strlen (src) + 1);
}
infact it uses memcpy: https://code.woboq.org/gcc/libgcc/memcpy.c.html
and here the magic...
void *
memcpy (void *dest, const void *src, size_t len)
{
char *d = dest;
const char *s = src;
while (len--)
*d++ = *s++;
return dest;
}
and strlen: https://code.woboq.org/userspace/glibc/string/strlen.c.html
You can use memcpy() to copy memory directly, like in Memcpy, string and terminator and https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html In C any string has to be terminated by \0 (sentinel value)
#include<stdio.h>
#include<string.h>
int main()
{
char source[] = "World";
char destination[] = "Hello ";
/* Printing destination string before memcpy */
printf("Original String: %s\n", destination);
/* Copies contents of source to destination */
memcpy (destination, source, sizeof(source));
/* Printing destination string after memcpy */
printf("Modified String: %s\n", destination);
return 0;
}
source : https://www.educative.io/edpresso/c-copying-data-using-the-memcpy-function-in-c
Is there way how to make my string to even size?
EDIT:
I need a few string in struct that have even length. So something like:
struct msg { char * first; char * second; char * third; };
so it is in the end something like first string "hi\0\0" second string "hello\0" third string "byebye\0\0" and i need to change them anytime+they are dynamic allocated.
Create a strdup_even().
Allocate memory as needed to copy the string, plus maybe 1 more to make "even".
char *strdup_even(const char *str) {
size_t len = strlen(str) + 1; // Size needed for the _string_
size_t len2 = len + len % 2; // Even allocation size
char *copy = malloc(len2);
if (copy) {
memcpy(copy, str, len);
if (len2 > len) {
copy[len] = '\0';
}
}
return copy;
}
Sample usage
struct msg m;
m.first = strdup_even("hi");
m.second = strdup_even("hello");
Use malloc() and realloc():
char *string = malloc(STRING_SIZE);
strcpy(string, "hi");
string = realloc(string, STRING_SIZE+1);
string[STRING_SIZE] = '\0';
I am using the below function to replace a sub-string in a given string
void ReplaceSubStr(char **inputString, const char *from, const char *to)
{
char *result = NULL;
int i, cnt = 0;
int tolen = strlen(to);
int fromlen = strlen(from);
if (*inputString == NULL)
return;
// Counting the number of times old word
// occur in the string
for (i = 0; (*inputString)[i] != '\0'; i++)
{
if (strstr((&(*inputString)[i]), from) == &(*inputString)[i])
{
cnt++;
// Jumping to index after the old word.
i += fromlen - 1;
}
}
// Making new string of enough length
result = (char *)malloc(i + cnt * (tolen - fromlen) + 1);
if (result == NULL)
return;
memset(result, 0, i + cnt * (tolen - fromlen) + 1);
i = 0;
while (&(*inputString))
{
// compare the substring with the result
if (strstr(*inputString, from) == *inputString)
{
strncpy(&result[i], to, strlen(to));
i += tolen;
*inputString += fromlen;
}
else
{
result[i++] = (*inputString)[0];
if ((*inputString)[1] == '\0')
break;
*inputString += 1;
}
}
result[i] = '\0';
*inputString = result;
return;
}
The problem with the above function is memory leak. Whatever memory is allocated for inputString will be lost after this line.
*inputString = result;
since I am using strstr and moving pointer of inputString *inputString += fromlen; inputString is pointing to NULL before the above line. So how to handle memory leak here.
Note: I dont want to return the new memory allocated inside the function. I need to alter the inputString memory based on new length.
You should use a local variable to iterate over the input string and avoid modifying *inputString before the final step where you free the previous string and replace it with the newly allocated pointer.
With the current API, ReplaceSubStr must be called with the address of a pointer to a block allocated with malloc() or similar. Passing a pointer to local storage or a string literal will have undefined behavior.
Here are a few ideas for improvement:
you could return the new string and leave it to the caller to free the previous one. In this case, you would take the input string by value instead of by address:
char *ReplaceSubStr(const char *inputString, const char *from, const char *to);
If the from string is empty, you should either insert the to string between each character of the input string or do nothing. As posted, your code has undefined behavior for this border case.
To check if the from string is present at offset i, use memcmp instead of strstr.
If cnt is 0, there is nothing to do.
You should return an error status for the caller to determine if memory could be allocated or not.
There is no need to initialize the result array.
avoid using strncpy(). This function has counter-intuitive semantics and is very often misused. Read this: https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/
Here is an improved version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int ReplaceSubStr(char **inputString, const char *from, const char *to) {
char *input = *inputString;
char *p, *q, *result;
size_t cnt;
size_t tolen = strlen(to);
size_t fromlen = strlen(from);
if (input == NULL || fromlen == 0)
return 0;
// Counting the number of times old word occurs in the string
for (cnt = 0, p = input; (p = strstr(p, from)) != NULL; cnt++) {
p += fromlen;
}
if (cnt == 0) // no occurrence, nothing to do.
return 0;
// Making new string of enough length
result = (char *)malloc(strlen(input) + cnt * (tolen - fromlen) + 1);
if (result == NULL)
return -1;
for (p = input, q = result;;) {
char *p0 = p;
p = strstr(p, from);
if (p == NULL) {
strcpy(q, p0);
break;
}
memcpy(q, p0, p - p0);
q += p - p0;
memcpy(q, to, tolen);
q += tolen;
p += fromlen;
}
free(*inputString);
*inputString = result;
return 0;
}
int main() {
char *p = strdup("Hello world!");
ReplaceSubStr(&p, "l", "");
printf("%s\n", p); // prints Heo word!
free(p);
return 0;
}
You cannot obviously free the input as it can be a literal, some memory you don't control. That would cripple your function even more than now.
You could return the old value of inputString so you'd be able to free it if needed.
char *ReplaceSubStr(char **inputString, const char *from, const char *to)
{
char *old_string = *inputString;
...
return old_string;
}
The caller is responsible to free the contents of old_string if needed.
If not needed (we have to workaround the char ** input by assigning a valid writable array to a pointer to be able to pass this pointer:
char input[]="hello world";
char *ptr = input;
ReplaceSubStr(&ptr, "hello", "hi");
// input is now "hi world" in a different location
free(ptr); // when replaced string isn't needed
if needed:
char *input = strdup("hello world");
char *old_input = ReplaceSubStr(&input, "hello", "hi");
free(old_input);
or just
free(ReplaceSubStr(&input, "hello", "hi"));
then always (when replaced string isn't needed):
free(input);
The only constraint is that you cannot use a constant string literal as input (const char *input = "hello world") because of the prototype & the possible return of a char * to pass to free.
I try to code my own concatenation function in C without library, but I have issue and I don't know where it comes from.
To do my function I use pointers of char.
This is my Code :
#include <stdio.h>
#include <stdlib.h>
int longueur(char *str)
{
int i =0;
while(str[i] != '\0')
{
i++;
}
return i;
}
void concat(char* source, char* dest)
{
int longStr1 = (longueur(source));
int longStr2 = (longueur(dest));
int i=0, j=0;
char* temp = dest;
free(dest);
dest = (char*) realloc(dest, ((longStr1 + longStr2)* sizeof(char)));
/*dest[0] = temp[0]; <------ If I do this it will generate issue, so the bellow code too*/
while(temp[i] != '\0')
{
dest[i] = temp[i];
i++;
}
while(source[j] != '\0')
{
dest[i] = source[j];
i++;
j++;
}
dest[i] = '\0';
}
int main()
{
char *str1 = "World";
char *str2 = "Hello";
concat(str1, str2);
printf("-------------\n%s", str2);
return 0;
}
EDIT
I read all your answer, so I changed my concat function to :
void concat(char* source, char* dest)
{
int longStr1 = (longueur(source));
int longStr2 = (longueur(dest));
int i=0, j=0;
dest = (char*) malloc((longStr1 + longStr2)* sizeof(char) + sizeof(char));
while(dest[i] != '\0')
{
dest[i] = dest[i];
i++;
}
while(source[j] != '\0')
{
dest[i] = source[j];
i++;
j++;
}
dest[i] = '\0';
}
Now I don't have issue but my code only display "Hello"
In addition to all the good comments and solutions: realloc can give you a different pointer and you must return that pointer. So your function signature should be:
void concat(char* source, char** dest)
{
int longStr1 = (longueur(source));
int longStr2 = (longueur(dest));
int i=0, j=0;
char* temp = *dest, *temp2;
if ((temp2 = realloc(dest, ((longStr1 + longStr2)+1))==NULL) return;
*dest= temp2;
while(temp[i] != '\0')
{
*dest[i] = temp[i];
i++;
}
while(source[j] != '\0')
{
*dest[i] = source[j];
i++;
j++;
}
*dest[i] = '\0';
}
..and this assumes the function will only be called with a dest that was allocated with malloc. And sizeof(char) is always 1. (This resulting function is not optimal.)
--EDIT--
Below the correct, optimized version:
void concat(char* source, char** dest)
{
int longSrc = longueur(source);
int longDst = longueur(dest);
char *pDst, *pSrc;
if ((pDst = realloc(*dest, longSrc + longDst + 1))==NULL) return;
if (pDst != *dest) *dest= pDst;
pDst += longSrc;
pSrc= source;
while(pSrc)
*pDst++ = *pSrc++;
*pDst = '\0';
}
In your code
free(dest);
and
dest = (char*) realloc(dest, ((longStr1 + longStr2)* sizeof(char)));
invokes undefined behavior as none of them use a pointer previously allocated by malloc() or family.
Mostly aligned with your approach, you need to make use of another pointer, allocate dynamic memory and return that pointer. Do not try to alter the pointers received as parameters as you've passed string literals.
That said, you need to have some basic concepts clear first.
You need not free() a memory unless it is allocated through malloc() family.
You need to have a char extra allocated to hold the terminating null.
Please see this discussion on why not to cast the return value of malloc() and family in C..
If your concatenation function allocates memory, then, the caller needs to take care of free()-ing the memory, otherwise it will result in memory leak.
After you have freed dest here:
free(dest);
You cannot use this pointer in following call to realloc:
dest = (char*) realloc(dest, ((longStr1 + longStr2)* sizeof(char)));
/*dest[0] = temp[0]; <------ If I do this it will generate issue, so the bellow code too*/
man realloc
void *realloc(void *ptr, size_t size);
The realloc() function changes the size of the memory block
pointed to by ptr to size bytes. (...)
But this pointer is invalid now and you cannot use it anymore. When you call free(dest), the memory dest points to is being freed, but the value of dest stays untouched, making the dest a dangling pointer. Accessing the memory that has already been freed produces undefined behavior.
NOTE:
Even if free(dest) is technically valid when called on pointer to memory allocated by malloc (it is not an error in your function to call free(dest) then), it is incorrect to use this on pointer to literal string as you do in your example (because str2 points to string literal it is an error to pass this pointer to function calling free on it).
Given your original use, perhaps you would find a variant like this useful
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
size_t longueur ( const char * str ) { /* correct type for string lengths */
size_t len = 0;
while (*str++ != '\0') ++len;
return len;
}
char * concat ( const char * first, const char * second ) {
const char * s1 = first ? first : ""; /* allow NULL input(s) to be */
const char * s2 = second ? second : ""; /* treated as empty strings */
size_t ls1 = longueur(s1);
size_t ls2 = longueur(s2);
char * result = malloc( ls1 + ls2 + 1 ); /* +1 for NUL at the end */
char * dst = result;
if (dst != NULL) {
while ((*dst = *s1++) != '\0') ++dst; /* copy s1\0 */
while ((*dst = *s2++) != '\0') ++dst; /* copy s2\0 starting on s1's \0 */
}
return result;
}
int main ( void ) {
const char *str1 = "Hello";
const char *str2 = " World";
char * greeting = concat(str1, str2);
printf("-------------\n%s\n-------------\n", greeting);
free(greeting);
return 0;
}
In this variant, the two inputs are concatenated and the result of the concatenation is returned. The two inputs are left untouched.
how to free dynamic memory allocated inside function
after finishing execution
i allocated two char * str2R & str4R
and my function is
char * MMP(char * index)
{
char* str1= "AT+CMGR=";
char* str2R = (char *) malloc(1 + strlen(str1)+ strlen(index) );
strcpy(str2R, str1);
strcat(str2R, index);
char* str3="\r";
char* str4R = (char *) malloc(1 + strlen(str2R)+ strlen(str3) );
strcpy(str4R, str2R);
strcat(str4R, str3);
return str4R;
};
when i call
free(str2R);
free(str4R);
in main or in another file after calling the function
this error appears
error: str2R undeclared (first use in this function)
thanks in advance
You do not need to allocate two char* buffers, one will suffice. Then caller needs to free() the returned char* when it is done using it.
Try this:
char * MMP(char * index)
{
char* str1 = "AT+CMGR=";
char* str3 = "\r";
char* str2R = (char *) malloc(strlen(str1) + strlen(index) + strlen(str3) + 1);
if (str2R)
{
strcpy(str2R, str1);
strcat(str2R, index);
strcat(str2R, str3);
}
return str2R;
}
char *str = MMP("some value");
...
free(str);
With that said, the logic inside of MMP() would be better served using snprintf() instead of strcpy() and strcat():
char * MMP(char * index)
{
char* fmt = "AT+CMGR=%s\r";
char* str2R = NULL;
int len = snprintf(NULL, 0, fmt, index);
if (len > 0)
{
++len;
str2R = (char *) malloc(len);
if (str2R)
snprintf(str2R, len, fmt, index);
}
return str2R;
}