Realloc, char**, segfault - c

There's a function. It is add_lexem and adds an element (char *) in the end of specified array and. If no memory left, it allocates some extra memory (100 * sizeof(char *)). That function causes segfault, which is the problem.
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
void add_lexem(char **lexems, int *lexemsc, int *lexem_n, const char *lexem)
{
if (*lexem_n >= *lexemsc) {
lexems = realloc(lexems, sizeof(char *) * (*lexemsc + 100));
*lexemsc += 100;
}
char *for_adding = malloc(sizeof(char) * strlen(lexem));
strcpy(for_adding, lexem);
lexems[*lexem_n] = for_adding;
(*lexem_n)++;
}
int main(void)
{
char **D = malloc(sizeof(char *) * 2);
int lexemsc = 2;
int lexem_n = 0;
add_lexem(D, &lexemsc, &lexem_n, "MEOW");
printf("%s\n", D[0]);
add_lexem(D, &lexemsc, &lexem_n, "BARK");
printf("%s\n", D[1]);
// in this place lexem_n becomes equal lexemsc
add_lexem(D, &lexemsc, &lexem_n, "KWARK");
printf("%s\n", D[2]);
return 0;
}
The output must be
MEOW
BARK
KWARK
but it is
MEOW
BARK
Segmentation fault (core dumped)

You're passing your lexeme parameter by value, when it should be by address:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
// removed unused void ccat(char *str, char c)
void add_lexem(char ***lexems, int *lexemsc, int *lexem_n, const char *lexem)
{
if (*lexem_n >= *lexemsc) {
*lexems = realloc(*lexems, sizeof(char *) * (*lexemsc + 100));
*lexemsc += 100;
}
char *for_adding = malloc(sizeof(char) * strlen(lexem)+1);
strcpy(for_adding, lexem);
(*lexems)[*lexem_n] = for_adding;
(*lexem_n)++;
}
int main(void)
{
char **D = malloc(sizeof(char *) * 2);
int lexemsc = 2;
int lexem_n = 0;
add_lexem(&D, &lexemsc, &lexem_n, "MEOW");
printf("%s\n", D[0]);
add_lexem(&D, &lexemsc, &lexem_n, "BARK");
printf("%s\n", D[1]);
// in this place lexem_n becomes equal lexemsc
add_lexem(&D, &lexemsc, &lexem_n, "KWARK");
printf("%s\n", D[2]);
return 0;
}
Output
MEOW
BARK
KWARK
Note: Triple indirection (i.e. a 3-start-programming) is not something to enter into lightly, though it actually fits what you appear to be trying to do here. Read the above code carefully and make sure you understand how it works.
Edit: added terminator space for added string. (don't know why I missed it, since it was what everyone else seemed to be catching on first-review, duh).
Note: See #wildplasser's answer to this question. Honestly it is the best way to do this, as it tightens the relationship between the string pointer array and the magnitude of said-same. If it is possible to retool your code to use that model, you should do so, and in-so-doing select that answer as the the "correct" solution.

Alternative to avoid the three-star-programming: put everything you need inside a struct:
struct wordbag {
size_t size;
size_t used;
char **bag;
};
void add_lexem(struct wordbag *wb, const char *lexem)
{
if (wb->used >= wb->size) {
wb->bag = realloc(wb->bag, (wb->size+100) * sizeof *wb->bag );
wb->size += 100;
}
wb->bag[wb->used++] = strdup(lexem);
}

The main problem is that you are passing D to the function by value: the assignment
lexems = realloc(...);
has no effect on D. In cases when realloc performs reallocation, D becomes a dangling pointer, so dereferencing it becomes undefined behavior.
You need to pass D by pointer in the same way that you pass lexemsc and &lexem_n, so that the realloc's effect would be visible inside the main function as well.
In addition, your add_lexem does not allocate enough memory for the string being copied: strlen does not count the null terminator, so these two lines
char *for_adding = malloc(sizeof(char) * strlen(lexem));
strcpy(for_adding, lexem);
write '\0' one byte past the allocated space.

The problem may come from :
char *for_adding = malloc(sizeof(char) * strlen(lexem));
strcpy(for_adding, lexem);
try char *for_adding = malloc(sizeof(char) * (strlen(lexem)+1)); to leave some space for the '\0 character.
Edit : and #WhozCraig seems to be right !
Bye,

Related

Memory management in replace function

I'm trying to make a replace function in C. I know there are many out there that I could copy, but I decided to make my own function in order to practice.
However, I'm stuck at this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void replace_content(char *rep, char *with, char **text) {
int len_rep = strlen(rep);
int len_with = strlen(with);
char *p = *text;
int new_text_size = 0;
char *new_text = malloc(new_text_size);
do {
if (!strncmp(p, rep, len_rep)) {
new_text_size += len_with;
new_text = (char *) realloc(new_text, new_text_size + 1);
strcat(new_text, with);
p += len_rep;
} else {
new_text_size++;
new_text = (char *) realloc(new_text, new_text_size);
new_text[new_text_size-1] = *p;
p++;
}
} while (*p != '\0');
*text = malloc(new_text_size);
strcpy(*text, new_text);
}
int main() {
printf("Testing a replace function:\n");
char *text =
"<serviceName>\n"
" <label1>a</label1>\n"
" <label2>b</label2>\n"
" <label3>c</label3>\n"
"</serviceName>\n";
printf("Before replace:\n%s", text);
replace_content("serviceName>", "serviceNameResponse>", &text);
printf("After replace:\n%s", text);
return 0;
}
This is the output I'm seeing so far:
Testing a replace function:
Before replace:
<serviceName>
<label1>a</label1>
<label2>b</label2>
<label3>c</label3>
</serviceName>
After replace:
<0�serviceNameRespons
<label1>a</label1>
<label2>b</label2>
<label3>c</label3>
</serviceNameResponse>
My guess is that I'm doing something wrong with dynamic memory, but the more I look into my code the more confused I am.
These two statements are problematic:
new_text = (char *) realloc(new_text, new_text_size + 1);
strcat(new_text, with);
The first problem is that you should never assign back directly to the pointer you reallocate. That is because realloc may fail and return NULL, making you lose the original pointer.
The second problem is that new_text doesn't initially point to a null-terminated string, which makes the call to strcat undefined behavior.
There is also a problem in the else branch:
new_text = (char *) realloc(new_text, new_text_size);
new_text[new_text_size-1] = *p;
Besides the same problem with reassigning back to the pointer being reallocated, you don't terminate the string in new_text.
May the reason is malloc(0) in line 10 char *new_text = malloc(new_text_size);.
The malloc() function allocates size bytes and returns a pointer to
the allocated memory. The memory is not initialized. If size is 0,
then malloc() returns either NULL, or a unique pointer value that
can later be successfully passed to free().
I suggest using char *new_text = NULL; instead.

Free first element of array

When I allocate an array using malloc, is there a way to only free the first element(s) of the array?
A small example:
#include <stdlib.h>
#include <string.h>
int main() {
char * a = malloc(sizeof(char) * 8);
strcpy(a, "foo bar");
// How I would have to do this.
char * b = malloc(sizeof(char) * 7);
strcpy(b, a+1);
free(a);
free(b);
}
Is there a way to free just the first char of a, so that I can use the rest of the string using a+1?
If you want to remove the first character of a, you could use memmove() to move the remainder of the characters in the string to the left by 1, and you could use realloc() to shrink the allocation if desired:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char * a = malloc(sizeof(char) * 8);
strcpy(a, "foo bar");
puts(a);
size_t rest = strlen(a);
memmove(a, a+1, rest);
/* If you must reallocate */
char *temp = realloc(a, rest);
if (temp == NULL) {
perror("Unable to reallocate");
exit(EXIT_FAILURE);
}
a = temp;
puts(a);
free(a);
return 0;
}
Update
#chux has made a couple of good points in the comments.
First, instead of exiting on a failure in realloc(), it may be better to simply continue without reassigning temp to a; after all, a does point to the expected string anyway, the allocated memory would just be a little larger than necessary.
Second, if the input string is empty, then rest will be 0. This leads to problems with realloc(a, rest). One solution would be to check for rest == 0 before modifying the string pointed to by a.
Here is a slightly more general version of the above code that incorporates these suggestions:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *s = "foo bar";
char *a = malloc(sizeof *a * (strlen(s) + 1));
strcpy(a, s);
puts(a);
size_t rest = strlen(a);
/* Don't do anything if a is an empty string */
if (rest) {
memmove(a, a+1, rest);
/* If you must reallocate */
char *temp = realloc(a, rest);
if (temp) {
a = temp;
}
}
puts(a);
free(a);
return 0;
}
Is there a way to free just the first char of a
No. You can not free the first character of a because it is of char type. Only pointer returned by malloc family function can be freed.
You can do this though.
char * a = malloc(sizeof(char) * 8);
strcpy(a, "foo bar");
char * b = malloc(strlen(a));
strcpy(b, a+1);
free(a);

Passing a pointer to array of string pointers

In the example below if I uncomment the printing of matches[1] and matches[2] in the print_and_modify function it fails(Illegal instruction: 4 on my Mac OS X mavericks).
What confuses me is why matches[0] works fine ? Any help is greatly appreciated.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void print_and_modify(char ***matches) {
printf("%s\n", *matches[0]);
/* printf("%s\n", *matches[1]); */
/* printf("%s", *matches[2]); */
}
int main(int argc, char **argv)
{
char **matches;
matches = malloc(3 * sizeof(char*));
matches[0] = malloc(10 * sizeof(char));
matches[1] = malloc(10 * sizeof(char));
matches[2] = malloc(10 * sizeof(char));
char *test1 = "test1";
char *test2 = "test2";
char *test3 = "test3";
strncpy(matches[0],test1,5);
strncpy(matches[1],test2,5);
strncpy(matches[2],test3,5);
print_and_modify(&matches);
printf("======\n");
printf("%s\n", matches[0]);
printf("%s\n", matches[1]);
printf("%s\n", matches[2]);
}
Please excuse the contrived example. I am trying to learn some C.
It's operator precedence: [] has higher precedence than *, so you need to force the desired precedence:
void print_and_modify(char ***matches) {
printf("%s\n", (*matches)[0]);
printf("%s\n", (*matches)[1]);
printf("%s", (*matches)[2]);
}
Demo.
Note that you do not need to pass a triple pointer, unless you wish to modify the allocated array itself. If you pass a double pointer, you would be able to modify the content of the individual strings, and also replace strings with other strings by de-allocating or re-allocating the char arrays.

Manipulating dynamic arrays in C

I am trying to solve StringMerge (PP0504B) problem from SPOJ (PL). Basically the problem is to write a function string_merge(char *a, char *b) that returns a pointer to an char array with string created from char arrays with subsequent chars chosen alternately (length of the array is the length of the shorter array provided as an argument).
The program I've created works well with test cases but it fails when I post it to SPOJ's judge. I'm posting my code here, as I believe it the problem is related to memory allocation (I'm still learning this part of C) - could you take a look at my code?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#define T_SIZE 1001
char* string_merge(char *a, char *b);
char* string_merge(char *a, char *b) {
int alen = strlen(a); int blen = strlen(b);
int len = (alen <= blen) ? alen : blen;
int i,j;
char *new_array = malloc (sizeof (char) * (len));
new_array[len] = '\0';
for(j=0,i=0;i<len;i++) {
new_array[j++] = a[i];
new_array[j++] = b[i];
}
return new_array;
}
int main() {
int n,c; scanf("%d", &n);
char word_a[T_SIZE];
char word_b[T_SIZE];
while(n--) {
scanf("%s %s", word_a, word_b);
char *x = string_merge(word_a, word_b);
printf("%s",x);
printf("\n");
memset(word_a, 0, T_SIZE);
memset(word_b, 0, T_SIZE);
memset(x,0,T_SIZE);
}
return 0;
}
Note: I'm compiling it with -std=c99 flag.
Off-by-one.
char *new_array = malloc (sizeof (char) * (len));
new_array[len] = '\0';
You're writing past the bounds of new_array. You must allocate space for len + 1 bytes:
char *new_array = malloc(len + 1);
Also, sizeof(char) is always 1, so spelling it out is superfluous, so are the parenthesis around len.
Woot, further errors!
So then you keep going and increment j twice within each iteration of the for loop. So essentially you end up writing (approximately) twice as many characters as you allocated space for.
Also, you're leaking memory by not free()ing the return value of string_merge() after use.
Furthermore, I don't see what the memsets are for, also I suggest you use fgets() and strtok_r() for getting the two words instead of scanf() (which doesn't do what you think it does).
char *new_array = malloc (sizeof (char) * (len*2 + 1));
new_array[len*2] = '\0';

C: realloc an array of string

I would like to reallocate an array of string with a function. I write a very simple program to demonstrate here. I expect to get the letter "b" to be output but I get NULL.
void gain_memory(char ***ptr) {
*ptr = (char **) realloc(*ptr, sizeof(char*) * 2);
*ptr[1] = "b\0";
}
int main()
{
char **ptr = malloc(sizeof(char*));
gain_memory(&ptr);
printf("%s", ptr[1]); // get NULL instead of "b"
return 0;
}
Thank you very much!
The [] operator has high priority than *, so change the code like this will work right.
(*ptr)[1] = "b";
P.S. "\0" is unnecessary.
You should put parentheses around *ptr in gain_memory:
(*ptr)[1] = "b\0";
You're not allocating any memory for the actual strings in your array of strings, you need to do something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void gain_memory(char ***ptr, int elem) {
*ptr = (char**)realloc(*ptr, 2*elem*sizeof(char*));
(*ptr)[1] = "b";
}
int main()
{
//How many strings in your array?
//Lets say we want 10 strings
int elem = 10;
char **ptr = malloc(sizeof(char*) * elem);
//Now we allocate memory for each string
for(int i = 0; i < elem; i++)
//Lets say we allocate 255 characters for each string
//plus one for the final '\0'
ptr[i] = malloc(sizeof(char) * 256);
//Now we grow the array
gain_memory(&ptr, elem);
printf("%s", ptr[1]);
return 0;
}

Resources