I wrote a program to concat two strings and make sure the buffer will double the size when there's no enough space.
char * strcat_ex(char * * dest, int * n, const char * src){
int dest_len = 0;
int src_len = 0;
if (*dest == NULL) *n = 0;
else dest_len = strlen(*dest);
if (src == NULL) return *dest;
else src_len = strlen(src);
if (dest_len + src_len + 1 > *n) {
//(1) malloc a new buffer of size 1 + 2 * (strlen(*dest) + strlen(src))
char * temp;
temp = (char*) malloc(1 + 2 * (strlen(*dest) + strlen(src)));
//(2) set '*n' to the size of the new buffer
*n = 1 + 2 * (strlen(*dest) + strlen(src));
//(3) copy '*dest' into the beginning of the new buffer
strcpy(temp, *dest);
//(4) free the memory '*dest', and then set '*dest' to point to the new buffer
free(*dest);
*dest = temp;
}
//(5) concatenate 'src' onto the end of '*dest'.
while (temp) temp++;
while ((temp++ = src++) =! '\0');
return *dest;}
and this code doesn't work. I got segmentation fault at "free(*dest)".
Please help. Thank you very much!
Here's the main function:
int main(int argc, char * * argv){
printf("\nTesting strcat_ex(...)\n");
char * str1;
str1 = "one";
char * str2;
str2 = "two";
int n;
n = strlen(str1);
printf("Before strcat_ex, str1 == %p (%s), str2 == %p (%s)\n", str1, str1, str2, str2);
strcat_ex(&(str1), &n, str2);
printf("After swap, str1 == %p (%s), str2 == %p (%s)\n", str1, str1, str2, str2);
return EXIT_SUCCESS;
}
The problem is that the initial value of str1 is a pointer to a literal string. That pointer cannot be freed. So the fix is to malloc space in main, e.g.
char *str1 = malloc( 100 ); // allocate an initial buffer
int n = 100; // the buffer has 100 bytes
strcpy( str1, "one" ); // put some text in the buffer
Related
Maybe it's a stupid question, but I get stuck here for a while.
Let's say freq_tostring() converts a word frequency freq into string, and freq_intostream() appends that string to the end of a stream.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
typedef struct {
char *word; // null-terminated
int freq;
} freq;
/**
* Constructor
*/
void new_freq(freq *fq, const char *word, const int freq) {
fq->word = (char *)malloc((strlen(word) + 1) * sizeof(char)); // +1 for null-terminator
strcpy(fq->word, word);
fq->freq = freq;
}
/**
* Free memory
*/
void dispose_freq(void *fq) {
freq *p = (freq *)fq;
free(p->word);
p->word = NULL;
}
/**
* snprintf() will terminate the string with a null character, unless buf_size is zero.
*/
char *freq_tostring(freq *fq) {
size_t wordlen = strlen(fq->word);
char *buffer = (char *)malloc(wordlen + 16); // maximum integer has 10 digits
snprintf(buffer, wordlen + 16, "[%s, %d]\n", fq->word, fq->freq);
return buffer;
}
/**
* Append the string of freq to the end of stream.
*/
void freq_intostream(void *elem, void *stream) {
freq *fq = (freq *)elem;
char *str = *(char **)stream;
size_t strsize = strlen(str);
// printf("Stream = \"%s\", length = %lu\n", str, strsize);
char *word = freq_tostring(fq);
size_t wordsize = strlen(word);
// printf("Element = \"%s\"%lu\n", word, wordsize);
char *temp = (char *)realloc(str, strsize + wordsize + 1);
strcpy(temp + strsize, word);
temp[strsize + wordsize] = '\0';
// printf("After strcpy(): \"%s\"\n", temp);
str = temp;
free(word);
}
int main(void) {
freq apple, banana, kiwi;
new_freq(&apple, "apple", 3);
new_freq(&banana, "banana", 2);
new_freq(&kiwi, "kiwi", 5);
char *buffer = (char *)malloc(1);
buffer[0] = '\0';
freq_intostream(&apple, &buffer);
freq_intostream(&banana, &buffer);
freq_intostream(&kiwi, &buffer);
assert(strlen(buffer) == 33);
assert(strcmp(buffer, "[apple, 3]\n[banana, 2]\n[kiwi, 5]\n") == 0);
dispose_freq(&apple);
dispose_freq(&banana);
dispose_freq(&kiwi);
free(buffer);
}
The weird thing is, when I run 10 times, it gives me about 9 pointer being realloc'd was not allocated, but maybe in 1~2 cases, everything is ok.
If I comment out the printf(), it shows that before appending the third element kiwi, the stream is empty, and that could be why realloc is failed. But I'm sure that I pass a pointer of char * stream to the freq_intostream() function, which is a char ** for sure. I can't find out what's the problem, anyone can help?
You've done the equivalent of i = j; i = 3; when you wanted j = 3;. Obviously, these don't do the same thing. Have a close look at the marked line in this funciton:
/**
* Append the string of freq to the end of stream.
*/
void freq_intostream(void *elem, void *stream) {
freq *fq = (freq *)elem;
char *str = *(char **)stream;
size_t strsize = strlen(str);
// printf("Stream = \"%s\", length = %lu\n", str, strsize);
char *word = freq_tostring(fq);
size_t wordsize = strlen(word);
// printf("Element = \"%s\"%lu\n", word, wordsize);
char *temp = (char *)realloc(str, strsize + wordsize + 1);
strcpy(temp + strsize, word);
temp[strsize + wordsize] = '\0';
// printf("After strcpy(): \"%s\"\n", temp);
str = temp; // OOPS!!
free(word);
}
You change the value of str, but str is a local to this function and its value is thrown away as soon as the function ends.
You wanted: *(char**)stream = temp; to change the value the caller passed you a pointer to.
This code would be much simpler if you get rid of all the casts. If elem were of type char **, you could just do *elem = temp; and the code would be much easier to understand.
I don't manage to copy a string in my function. Once I try to print the strings, nothing appears.
int read_exit_tr (){
char * buff = (char *) malloc (20 * sizeof(char));
//char * temp;
int r = read(0,buff,SIZE_LECTURE);
//temp = (char *) malloc (strlen(buff) + 1 );
//memcpy(buff,temp,20);
if (r > 0) {
printf("%s X\n",buff);
//printf("%s X\n",temp);
}else
printf("erreur");
free(buff);
// free(temp);
return 0;
}
In this version, buff is printed correctly. But once I uncomment the lines and print buff and temp, both are empty.
Thanks for reading, could you please help me?
int main(int argc, char *argv[]) {
if(argc!=3) {
printf("You must pass exactly three para \n");
return 0;
}
char *buffer = argv[1];
//printf("The length of the buffer string is %d\n",buflen);
char *mystring = argv[2];
//printf("The length of the user string is %d\n",len);
addstring(buffer, mystring);
return 0;
}
int addstring(char *buffer, char *mystring)
{
int buflen = strlen(buffer);
int len = strlen(mystring);
char *dest;
*dest = (char *)malloc(buflen + len + 1);
printf("The size of destination is %lu\n",sizeof(dest));
dest = strcpy(dest,buffer);
dest = (dest + buflen);
dest = strcpy(dest,mystring);
printf("The final string is %p",dest);
return 0;
}
In the above code, the function addstring(..) shoes this error Assignment makes integer from a pointer without a cast. I know I'm taking the value of a pointer and putting it in integer, but how may I do it to resolve this error?
Even after changing *dest to dest, your function addstring is not works properly.. Simply try like this
int addstring(char *buffer, char *mystring)
{
int buflen = strlen(buffer);
int len = strlen(mystring);
char *dest;
dest = (char *)malloc(buflen + len + 1);
printf("The size of destination is %d\n",sizeof(dest));
strcpy(dest,buffer);
strcat(dest,mystring);
printf("The final string is %s\n",dest);
return 0;
}
You have done
*dest = (char *)malloc(buflen + len + 1);
instead of
dest =malloc(buflen + len + 1);
Your program saying warning to me for this line
printf("The size of destination is %lu\n",sizeof(dest));
sizeof() return type is not long unsigned int.
So use %d or %u or %zu as a access specifier in printf() statement.
change
char *dest;
*dest = (char *)malloc(buflen + len + 1);
to
char *dest;
dest = (char *)malloc(buflen + len + 1);
EDIT: As #POW said, you need not cast the result of malloc
There are multiple issue in your code.
Please check the below code
int addstring(char *buffer, char *mystring)
{
int buflen = strlen(buffer);
int len = strlen(mystring);
char *dest;
/* No need to type-cast the malloc() */
dest = malloc(buflen + len + 1); /* *dest holds the value, dest holds the address */
printf("The size of destination is %lu\n",sizeof(dest));
strcpy(dest,buffer);
strcpy(dest+buflen,mystring);/* copy the second string to dest after buffer is copied */
printf("The final string is %s\n",dest); /*To print a string use %s, %p is to print pointer*/
return 0;
}
I have two strings that I would like to combine, removing duplicate substrings. Note that every two consecutive numbers constitute a substring. Consider string str1 and str2:
str1 = "#1#.1.2.3#1#.6.7.8"
str2 = "#1#.6.7.8#1#.5.6"
I would like to produce a combined string as:
comboStr = "#1#.1.2.3#1#.6.7.8#1#.5.6" (i.e. I removed the duplicate #1#.6.7.8).
I have written a small function that does this:
char *combine (char *nodehashkey ,char *ngbrhashkey)
{
char *suffix, *combo_hashkey;
char prefix[5], token[15];
short qid;
short len = strlen(nodehashkey);
combo_hashkey = (char*) malloc(sizeof(char) * (len+1));
strcpy(combo_hashkey, nodehashkey);
short offset = len;
sscanf(nodehashkey, "#%hd#", &qid);
sprintf(prefix, "#%hd#", qid);
printf("prefix: %s\n", prefix);
suffix = strtok(ngbrhashkey, prefix);
while (suffix != NULL)
{
strcpy(token, prefix);
strcpy(token + strlen(prefix), suffix);
int token_len = strlen(token);
if(strstr(nodehashkey, token) == NULL)
{
if(!(combo_hashkey = (char*) realloc (
combo_hashkey, sizeof(char) * (offset+token_len+1))))
printf("malloc failed!");
strncpy(combo_hashkey + offset, token, token_len+1);
offset += token_len;
combo_hashkey[offset] = '\0';
}
suffix = strtok(NULL, prefix);
}
return combo_hashkey;
}
In order to test it, I have tried the following. While, the first two calls to combine produce the correct combo string, the third call doesn't. In stead of producing #1#.1.6#1#.2.4#1#.3.5, it's producing #1#.1.6#1#.2.4#1#.6#1#.3.5
int main (int argc, char *argv[])
{
char *str1 = malloc(sizeof(char) * 8);
strcpy(str1, "#1#.1.6");
char *str2= malloc(sizeof(char) * 8);
strcpy(str2, "#1#.2.4");
char *str3 = malloc(sizeof(char) * 8);
strcpy(str3, "#1#.3.5");
str2 = combine(str1, str2);
str3 = combine(str1, str3);
char *weird = combine(str2, str3);
printf("weird: %s\n", weird);
}
I have traced the function again and I can not spot where the extra #1#.6 comes from.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *combine (const char *nodehashkey, const char *ngbrhashkey){
int i, dup, len, pos_count = 0;
const char *p1, *p2, *pos[64];
char *combo_hashkey, *p3;
if(!nodehashkey || !ngbrhashkey)
return NULL;
//store key position
pos[0] = p1 = nodehashkey;
while(*p1){
sscanf(p1, "#%*d#%*[.0123456789]%n", &len);
pos[++pos_count] = (p1 += len);
}
len = p1 - nodehashkey;
p2 = ngbrhashkey;
p3 = combo_hashkey = malloc(len + strlen(p2) + 1);
memcpy(p3, nodehashkey, len);
p3 += len;
while(*p2){
sscanf(p2, "#%*d#%*[.0123456789]%n", &len);
for(dup=i=0;i<pos_count;++i){
if(pos[i+1]-pos[i] == len && strncmp(pos[i], p2, len)==0){
dup = 1;
break;
}
}
if(!dup){
memcpy(p3, p2, len);
p3 += len;
}
p2 += len;
}
*p3 = '\0';
return combo_hashkey;
}
int main(){
char *str1, *str2, *str3;
str1 = combine("#1#.1.2.3#1#.6.7.8", "#1#.6.7.8#1#.5.6");
printf("%s\n", str1);//#1#.1.2.3#1#.6.7.8#1#.5.6
free(str1);
str2 = combine("#1#.1.6", "#1#.2.4");
str3 = combine("#1#.1.6", "#1#.3.5");
printf("str2:%s\n", str2);
printf("str3:%s\n", str3);
char *weird = combine(str2, str3);
printf("weird: %s\n", weird);//weird: #1#.1.6#1#.2.4#1#.3.5
free(str2);free(str3);free(weird);
return 0;
}
I am trying to read in from stdin (passing in value from a file). I am reading each character from the string and storing it into a dynamically allocated string pointer. When needed I realloc the memory. I am trying to get as many characters as possible. Though I can limit it to 100,000 chars. But the realloc fails after some iteration. But if I specify a chunk size big, say 1048567 during the first initialization in malloc, I am able to read the string completely. Why is this?
Below is my program:
#include <stdio.h>
#include <stdlib.h>
int display_mem_alloc_error();
enum {
CHUNK_SIZE = 31 //31 fails. But 1048567 passes.
};
int display_mem_alloc_error() {
fprintf(stderr, "\nError allocating memory");
exit(1);
}
int main(int argc, char **argv) {
int numStr; //number of input strings
int curSize = CHUNK_SIZE; //currently allocated chunk size
int i = 0; //counter
int len = 0; //length of the current string
int c; //will contain a character
char *str = NULL; //will contain the input string
char *str_cp = NULL; //will point to str
char *str_tmp = NULL; //used for realloc
str = malloc(sizeof(*str) * CHUNK_SIZE);
if (str == NULL) {
display_mem_alloc_error();
}
str_cp = str; //store the reference to the allocated memory
scanf("%d\n", &numStr); //get the number of input strings
while (i != numStr) {
if (i >= 1) { //reset
str = str_cp;
len = 0;
curSize = CHUNK_SIZE;
}
c = getchar();
while (c != '\n' && c != '\r') {
*str = (char *) c;
//printf("\nlen: %d -> *str: %c", len, *str);
str = str + 1;
len = len + 1;
*str = '\0';
c = getchar();
if (curSize / len == 1) {
curSize = curSize + CHUNK_SIZE;
//printf("\nlen: %d", len);
printf("\n%d \n", curSize); //NB: If I comment this then the program simply exits. No message is displayed.
str_tmp = realloc(str_cp, sizeof(*str_cp) * curSize);
if (str_tmp == NULL) {
display_mem_alloc_error();
}
//printf("\nstr_tmp: %d", str_tmp);
//printf("\nstr: %d", str);
//printf("\nstr_cp: %d\n", str_cp);
str_cp = str_tmp;
str_tmp = NULL;
}
}
i = i + 1;
printf("\nlen: %d", len);
//printf("\nEntered string: %s\n", str_cp);
}
str = str_cp;
free(str_cp);
free(str);
str_cp = NULL;
str = NULL;
return 0;
}
Thanks.
When you realloc
str_tmp = realloc(str_cp, sizeof(*str_cp) * curSize);
if (str_tmp == NULL) {
display_mem_alloc_error();
}
//printf("\nstr_tmp: %d", str_tmp);
//printf("\nstr: %d", str);
//printf("\nstr_cp: %d\n", str_cp);
str_cp = str_tmp;
str_tmp = NULL;
you let str_cp point to the new block of memory, but str still points into the old, now freed block. Thus when you access what str points to in the next iteration, you invoke undefined behaviour.
You need to save the offset of str with respect to str_cp, and after the reallocation, letstr point into the new block at its old offset.
And *str = (char *) c; is wrong, although there is a nonzero chance of it being functionally equivalent to the correct *str = c;.
*str = (char *) c;
This line is wrong.
str is a pointer to char and *str is a char but you are assigning a pointer to char to a char. This cannot be done in C.
Moreover:
scanf("%d\n", &numStr);
The \n in scanf call probably does not what you expect:
http://c-faq.com/stdio/scanfhang.html
And also:
str = str_cp;
free(str_cp);
free(str);
You have a double free here. After the assignment str and str_cp will have the same value so doing:
free(str_cp);
free(str);
is as if you do:
free(str);
free(str);
which is undefined behavior (you cannot free twice).