C: Losing content of char** after end of function [duplicate] - c

This question already has answers here:
Using realloc inside a function [duplicate]
(2 answers)
Closed 8 years ago.
I have a problem I can't solve. I split a string in substrings and put these substrings in an array. Everything goes fine until the search function ends. the strtok function makes perfect substrings and then everything is nicely putten in the array but when the function ends the array loses all his content. I've tried a lot of different things but nothing seems to work. I want the words array to keep his content when the search function ends and returns to main.
int main(void)
{
char** words=NULL;
char argument[26] = "just+an+example";
search(argument, words);
}
search(char* argument, char** words)
{
char* p = strtok (argument, "+");
int n_spaces = 0;
while (p)
{
words = realloc(words, sizeof(char*)* ++n_spaces);
if (words == NULL)
exit(-1); // memory allocation failed
words[n_spaces-1] = p;
p = strtok(NULL, "+");
}
// realloc one extra element for the last NULL
words = realloc(words, sizeof(char*)* (n_spaces+1));
words[n_spaces] = 0;
}

I'm guessing that you want words in main to point to an array of pointers to the places where the delimiter is. You need to pass in the address of the variable words to search, and inside search, modify the memory pointed at by the variable words.
Try this:
int main(void)
{
char** words = NULL;
char argument[26] = "just+an+example";
search(argument, &words);
}
search(char* argument, char*** words)
{
char* p = strtok (argument, "+");
int n_spaces = 0;
while (p)
{
*words = realloc(*words, sizeof(char*) ++n_spaces);
if (*words == NULL)
exit(-1); // memory allocation failed
(*words)[n_spaces-1] = p;
p = strtok(NULL, "+");
}
// realloc one extra element for the last NULL
*words = realloc(words, sizeof(char*)* (n_spaces+1));
(*words)[n_spaces] = 0;
}
I didn't review your logic in search at all, so you may not be done debugging yet.

I was doing af few things wrong. First of all in the main function when I called the search function I had to pass the adress of my array (&words). My second mistake was instead of copying the substrings itself I copied the pointers to the substrings. At the end of the function these pointers are freed so my array lost his content at the end of the function. To fix this I had to malloc every time I wanted to copy a new string to my array and use strcpy to copy the string where the pointer points to to my array.
int main(void)
{
char** words = NULL;
char argument[26] = "just+an+example";
search(argument, &words);
}
search(char* argument, char*** words)
{
char* p = strtok (argument, "+");
int n_spaces = 0;
while (p)
{
*words = realloc(*words, sizeof(char*) ++n_spaces);
if (*words == NULL)
exit(-1); // memory allocation failed
(*words)[n_spaces - 1] = malloc(sizeof(char)* (strlen(p) + 1));
strcpy((*words)[n_spaces - 1], p);
p = strtok(NULL, "+");
}
}

Related

free allocated memory in function

i have function which is written in c ,in this function i allocate 2 string as temp and found, but i cant free temp string.
i think it may due to using of temp in result array.
can any one helps me.
here is the function.
void split(char* input, char* delim, char** result,int size) {
char* tmp = malloc((strlen(input)) * sizeof(char));
char* found = malloc((strlen(input)) * sizeof(char));
tmp=strcpy(tmp, input);
// #pragma omp parallel for
for (int i=0; i<size; i++) {
found = strstr(tmp, delim);
if (found != NULL) {
int length = found - tmp;
result[i]=malloc((length+1) * sizeof(char));
result[i] = strncpy(result[i], tmp, length);
*(result[i] + length) = '\0';
tmp = found + strlen(delim);
} else {
result[i]=malloc(strlen(tmp) * sizeof(char));
result[i] =strncpy(result[i], tmp, strlen(tmp));
}
}
// free(tmp);
free(found);
}
here size is number of sub strings after split
when i remove the comment of this line:
// free(tmp);
then this err occurs:
munmap_chunk(): invalid pointer
Aborted (core dumped)
can i ask you to help me for writing correct split function
You do assignments to tmp. That means the pointer tmp might no longer point to the same location that malloc returned.
You need to pass the exact same pointer to free that was returned by malloc.
You have the same problem with found, you assign to it and possible change where it points.
Passing an invalid pointer to free leads to undefined behavior.
You also have another problem: You go out of bounds of the original memory allocated and pointed to by tmp. That's because you seem to have forgotten that strings in C are really called null-terminated strings.
When you allocate memory for a string, you need to include space for the null-terminator at the end. And it's not counted by strlen.
Going out of bounds of allocated memory also leads to undefined behavior.
The function does not make a sense.
For starters it invokes undefined behavior
char* tmp = malloc((strlen(input)) * sizeof(char));
char* found = malloc((strlen(input)) * sizeof(char));
tmp=strcpy(tmp, input);
//...
because you allocated to enough memory to store the terminating zero character '\0' of the string input in the character array tmp.
Secondly the function has a memory leak because at first memory was allocated and its address was assigned to the pointer found and then the pointer found was reassigned in the call of strstr in the for loop.
char* found = malloc((strlen(input)) * sizeof(char));
//...
// #pragma omp parallel for
for (int i=0; i<size; i++) {
found = strstr(tmp, delim);
//...
So the address of the early allocated memory is lost and the memory can not be freed.
And this for loop
for (int i=0; i<size; i++) {
is just senseless.
You may not call free neither for tmp nor for found. The pointer found does not point to a dynamically allocated memory and the pointer tmp is being changed within the for loop.
here is my new function. i wrote it in recursive mode.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int get_number_of_occurence(char* string, char* delim) {
char* found = strstr(string, delim);
if(found == NULL || strcmp(found,delim) ==0 ||found =="" ){
return 0;
}else{
return 1+get_number_of_occurence(found+strlen(delim), delim);
}
}
int split(char* input, char* delim, char** result,int array_idx) {
char* found= strstr(input, delim);
if (found==""||strlen(input)==0){
return 0;
}else if(found == NULL){
result[array_idx]=malloc(strlen(input)+1 * sizeof(char));
strncpy(result[array_idx], input, strlen(input));
*(result[array_idx] + strlen(input)) = '\0';
return 0;
}else{
int length = found - input;
result[array_idx]=malloc((length+1) * sizeof(char));
strncpy(result[array_idx], input, length);
*(result[array_idx] + length) = '\0';
return split(found+strlen(delim),delim,result,array_idx+1);
}
}
int main () {
char * delim = "ooo";
char * input="ssooonn";
int size = get_number_of_occurence(input, delim);
printf("size is : %d \n",size);
char *splitted_values[size+1];
split(input, delim,splitted_values,0);
for (int i=0; i<(size+1); i++) {
printf("%s\n",splitted_values[i]);
free(splitted_values[i]);
}
}
in this code, first i count the number of occurrence of delimiter.
then i create array in that size and fill it with the help of split function.
thanks for helping.

Function returns char**s, running the function twice causes the return value to differ

Description of what my function attempts to do
My function gets a string for example "Ab + abc EF++aG hi jkL" and turns it into ["abc", "hi"]
In addition, the function only takes into account letters and the letters all have to be lowercase.
The problem is that
char* str1 = "Ab + abc EF++aG hi jkL";
char* str2 = "This is a very famous quote";
char** tokens1 = get_tokens(str1);
printf("%s", tokens1[0]); <----- prints out "abc" correct output
char** tokens2 = get_tokens(str2);
printf("%s", tokens1[0]); <----- prints out "s" incorrect output
get_tokens function (Returns the 2d array)
char** get_tokens(const char* str) {
// implement me
int num_tokens = count_tokens(str);
char delim[] = " ";
int str_length = strlen(str);
char* new_str = malloc(str_length);
strcpy(new_str, str);
char* ptr = strtok(new_str, delim);
int index = 0;
char** array_2d = malloc(sizeof(char*) *num_tokens);
while (ptr != NULL){
if (check_string(ptr) == 0){
array_2d[index] = ptr;
index++;
}
ptr = strtok(NULL, delim);
}
free(new_str);
new_str = NULL;
free(ptr);
ptr = NULL;
return array_2d;
}
count_tokens function (returns the number of valid strings)
for example count_tokens("AB + abc EF++aG hi jkL") returns 2 because only "abc" and "hi" are valid
int count_tokens(const char* str) {
// implement me
//Seperate string using strtok
char delim[] = " ";
int str_length = strlen(str);
char* new_str = malloc(str_length);
strcpy(new_str, str);
char* ptr = strtok(new_str, delim);
int counter = 0;
while (ptr != NULL){
if (check_string(ptr) == 0){
counter++;
}
ptr = strtok(NULL, delim);
}
free(new_str);
return counter;
}
Lastly check_string() checks if a string is valid
For example check_string("Ab") is invalid because there is a A inside.
using strtok to split "Ab + abc EF++aG hi jkL" into separate parts
int check_string(char* str){
// 0 = false
// 1 = true
int invalid_chars = 0;
for (int i = 0; i<strlen(str); i++){
int char_int_val = (int) str[i];
if (!((char_int_val >= 97 && char_int_val <= 122))){
invalid_chars = 1;
}
}
return invalid_chars;
}
Any help would be much appreciated. Thank you for reading.
If you have any questions about how the code works please ask me. Also I'm new to stackoverflow, please tell me if I have to change something.
You have a few problems in your code. First I'll repeat what I've said in the comments:
Not allocating enough space for the string copies. strlen does not include the NUL terminator in its length, so when you do
char* new_str = malloc(str_length);
strcpy(new_str, str);
new_str overflows by 1 when strcpy adds the '\0', invoking undefined behavior. You need to allocate one extra:
char* new_str = malloc(str_length + 1);
strcpy(new_str, str);
You should not free any pointer returned from strtok. You only free memory that's been dynamically allocated using malloc and friends. strtok does no such thing, so it's incorrect to free the pointer it returns. Doing so also invokes UB.
Your final problem is because of this:
// copy str to new_str, that's correct because strtok
// will manipulate the string you pass into it
strcpy(new_str, str);
// get the first token and allocate size for the number of tokens,
// so far so good (but you should check that malloc succeeded)
char* ptr = strtok(new_str, delim);
char** array_2d = malloc(sizeof(char*) *num_tokens);
while (ptr != NULL){
if (check_string(ptr) == 0){
// whoops, this is where the trouble starts ...
array_2d[index] = ptr;
index++;
}
// get the next token, this is correct
ptr = strtok(NULL, delim);
}
// ... because you free new_str
free(new_str);
ptr is a pointer to some token in new_str. As soon as you free(new_str), Any pointer pointing to that now-deallocated memory is invalid. You've loaded up array_2d with pointers to memory that's no longer allocated. Trying to access those locations again invokes undefined behavior. There's two ways I can think of off the top to solve this:
Instead of saving pointers that are offsets to new_str, find the same tokens in str (the string from main) and point to those instead. Since those are defined in main, they will exist for as long as the program exists.
Allocate some more memory, and strcpy the token into array_2d[index]. I'll demonstrate this below:
while (ptr != NULL){
if (check_string(ptr) == false)
{
// allocate (enough) memory for the pointer at index
array_2d[index] = malloc(strlen(ptr) + 1);
// you should _always_ check that malloc succeeds
if (array_2d[index] != NULL)
{
// _copy_ the string pointed to by ptr into our new space rather
// than simply assigning the pointer
strcpy(array_2d[index], ptr);
}
else { /* handle no mem error how you want */ }
index++;
}
ptr = strtok(NULL, delim);
}
// now we can safely free new_str without invalidating anything in array_2d
free(new_str);
I have a working demonstration here. Note some other changes in the demo:
#include <stdbool.h> and used that instead of 0 and 1 ints.
Changed your get_tokens function a bit to "return" the number of tokens. This is useful in main for printing them out.
Replaced the ASCII magic numbers with their characters.
Removed the useless freedPointer = NULL lines.
Changed your ints to size_t types for everything involving a size.
One final note, while this is a valid implementation, it's probably doing a bit more work than it needs to. Rather than counting the number of tokens in a first pass, then retrieving them in a second pass, you can surely do everything you want in a single pass, but I'll leave that as an exercise to you if you're so inclined.

Dynamically allocated array of strings memory doesn't seem to be working

I'm trying to have this function read a sentence and store each word into an array of strings. I store the sentence in line:
char** storewords(char* line){
char** newArr = (char**) malloc(sizeof(char*));
free(word);
return newArr;
}
I later call this function and try to print each word in the array:
main {
// ........ //
//function to get a line into line//
}
void printArr(char** newArr) {
int i = 0;
}
}
I use while (newArr[i] != NULL) in order to tell the program to iterate through the array until encountering a NULL item.
The memory seems to be allocated weirdly, because when I print it out, some words don't seem to print sometimes but other times works perfectly.
For example, if I input "hello hi", I get:
newArr 0:
newArr 1: hi
and "hello my name is" will get:
newArr 0: hello
newArr 1: my
newArr 2: name
newArr 3:
but if I input something longer like "hello my name is stackoverflow", I get the correct results.
If I understand the idea behind your storewords correct, you want to:
a) Start with a single char pointer
b) Add an extra char pointer each time you call realloc
so that you can set the last char pointer to NULL so that it serves as an "end-of-array" marker.
If that is your intention, the problem is the realloc.
char** newArr = (char**) malloc(sizeof(char*)); // Now you have 1 char pointer
char* word;
int count = 0; // Notice that you (correctly) initialize count to zero
word = strtok(line, " ");
while (word != NULL) {
newArr = (char**) realloc(newArr, sizeof(char*) * (count + 1));
// The first time you execute the realloc, you want to
// increase the number of char pointers from 1 to 2.
// But count is zero so count + 1 is only 1.
// In other words, you only got 1 element but
// you wanted 2 elements.
So instead do:
newArr = (char**) realloc(newArr, sizeof(char*) * (count + 2));
as count is "2 behind" the number of elements you want.
BTW: Doing realloc directly into destination variable is bad. Always do it in two a temp variable. Check for NULL. If not NULL, assign the temp variable to the destination.
BTW: No need to cast the value returned by realloc and malloc
BTW: Remove free(word); It does nothing and you don't want to free anything here.
So with the above in mind, your function could be:
char** storewords(char* line){
char** tmp;
char** newArr = malloc(sizeof(char*));
char* word;
int count = 0;
word = strtok(line, " ");
while (word != NULL) {
tmp = realloc(newArr, sizeof(char*) * (count + 2));
if (tmp == NULL)
{
// realloc failed - add error handling - for now just exit
exit(1);
}
newArr = tmp;
newArr[count] = malloc(strlen(word) * sizeof(char) + 1);
// put the word in array
sscanf(word, "%s", newArr[count]);
count++;
word = strtok(NULL, " ");
}
newArr[count] = NULL; //set the last item in the array as null
return newArr;
}
while you play with string you should be always very careful. Here you are using pointer of pointer so use them like pointer rather use as array and mix and match. While you write a program, arrange the algorithm first how you are going to implement it step by step and write it down in a paper, which is call as procedural design as well. I have modified your program below see your mistakes here. Also see how I just use the pointer of pointers as pointer only but not like array. So I leave the code for printArr to you to change it from array to pointer so that you can enjoy it. GOOD LUCK!!
char** storewords(char* line){
char** newArr = (char**) malloc(sizeof(char*));
char* word;
int count = 1;
word = strtok(line, " ");
*newArr = word; //store the pointer of word at the first location
while (word != NULL) {
newArr = (char**) realloc(newArr, sizeof(char*) * (count + 1));
//newArr[count] = (char*)malloc(strlen(word) * sizeof(char) + 1);//you dont need this line at all
// put the word in array
//sscanf(word, "%s", newArr[count]);
word = strtok(NULL, " ");//get the next word
*(newArr+count)=word;//store the next word here
count++;
}
*(newArr+count) = NULL; //set the last item in the array as null
free(word);
return newArr;
}
void printArr(char** newArr) {
int i = 0;
while (newArr[i] != NULL) {
printf("newArr %d: %s\n", i, newArr[i]);
i++;
}
}
int main() {
// ........ //
//function to get a line into line//
char *line = malloc(100);
strcpy(line, "Hello world how are you!");
char** newArr = storewords(line);
printArr(newArr);
return 0;
}

_platform_memmove$VARIANT$Unknown () from /usr/lib/system/libsystem_platform.dylib changing content of character pointer

I am trying to write a program that accepts a user string and then reverses the order of the words in the string and prints it. My code works for most tries, however, it seg faults on certain occasions, for the same input.
On stepping through I found that the content of character pointers words[0] and words[1] are getting changed to garbage values/Null.
I set a watch point on one of the word[1] and wprd[0] character pointers that are getting corrupted (incorrect address), and can see that the content of these pointers changes at '_platform_memmove$VARIANT$Unknown () from /usr/lib/system/libsystem_platform.dylib'. I cant figure out how this gets invoked and what's causing the content of the pointers to be overwritten.
I have posted my code below and would like any assistance in figuring out where I am going wrong. I am sorry about the indentation issues.
char* reverseWords(char *s) {
char** words = NULL;
int word_count = 0;
/*Create an array of all the words that appear in the string*/
const char *delim = " ";
char *token;
token = strtok(s, delim);
while(token != NULL){
word_count++;
words = realloc(words, word_count * sizeof(char*));
if(words == NULL){
printf("malloc failed\n");
exit(0);
}
words[word_count - 1] = strdup(token);
token = strtok(NULL, delim);
}
/*Traverse the list backwards and check the words*/
int count = word_count;
char *return_string = malloc(strlen(s) + 1);
if(return_string == NULL){
printf("malloc failed\n");
exit(0);
}
int offset = 0;
while(count > 0){
memcpy((char*)return_string + offset, words[count - 1], strlen(words[count - 1]));
free(words[count - 1]);
offset += strlen(words[count - 1]);
if(count != 1){
return_string[offset] = ' ';
offset++;
}
else {
return_string[offset] = '\0';
}
count--;
}
printf("%s\n",return_string);
free(words);
return return_string;
}
int main(){
char *string = malloc(1000);
if(string == NULL){
printf("malloc failed\n");
exit(0);
}
fgets(string, 1000, stdin);
string[strlen(string)] = '\0';
reverseWords(string);
return 0;
}
The problem is that the line
char *return_string = malloc(strlen(s) + 1);
doesn't allocate nearly enough memory to hold the output. For example, if the input string is "Hello world", you would expect strlen(s) to be 11. However, strlen(s) will actually return 5.
Why? Because strtok modifies the input line. Every time you call strtok, it finds the first delimiter and replaces it with a NUL character. So after the first while loop, the input string looks like this
Hello\0world\0
and calling strlen on that string will return 5.
So, the result_string is too small, and one or more memcpy will write past the end of the string, resulting in undefined behavior, e.g. a segmentation fault. The reason for the error message about memmove: the memcpy function internally invokes memmove as needed.
As #WhozCraig pointed out in the comments, you also need to make sure that you don't access memory after a call to free, so you need to swap these two lines
free(words[count - 1]);
offset += strlen(words[count - 1]);

easy c question: compare first char of a char array

How can I compare the first letter of the first element of a char**?
I have tried:
int main()
{
char** command = NULL;
while (true)
{
fgets(line, MAX_COMMAND_LEN, stdin);
parse_command(line, command);
exec_command(command);
}
}
void parse_command(char* line, char** command)
{
int n_args = 0, i = 0;
while (line[i] != '\n')
{
if (isspace(line[i++]))
n_args++;
}
for (i = 0; i < n_args+1; i++)
command = (char**) malloc (n_args * sizeof(char*));
i = 0;
line = strtok(line," \n");
while (line != NULL)
{
command[i++] = (char *) malloc ( (strlen(line)+1) * sizeof(char) );
strcpy(command[i++], line);
line = strtok(NULL, " \n");
}
command[i] = NULL;
}
void exec_command(char** command)
{
if (command[0][0] == '/')
// other stuff
}
but that gives a segmentation fault. What am I doing wrong?
Thanks.
Could you paste more code? Have you allocated memory both for your char* array and for the elements of your char* array?
The problem is, you do allocate a char* array inside parse_command, but the pointer to that array never gets out of the function. So exec_command gets a garbage pointer value. The reason is, by calling parse_command(line, command) you pass a copy of the current value of the pointer command, which is then overwritten inside the function - but the original value is not affected by this!
To achieve that, either you need to pass a pointer to the pointer you want to update, or you need to return the pointer to the allocated array from parse_command. Apart from char*** looking ugly (at least to me), the latter approach is simpler and easier to read:
int main()
{
char** command = NULL;
while (true)
{
fgets(line, MAX_COMMAND_LEN, stdin);
command = parse_command(line);
exec_command(command);
}
}
char** parse_command(char* line)
{
char** command = NULL;
int n_args = 0, i = 0;
while (line[i] != '\n')
{
if (isspace(line[i++]))
n_args++;
}
command = (char**) malloc ((n_args + 1) * sizeof(char*));
i = 0;
line = strtok(line," \n");
while (line != NULL)
{
command[i] = (char *) malloc ( (strlen(line)+1) * sizeof(char) );
strcpy(command[i++], line);
line = strtok(NULL, " \n");
}
command[i] = NULL;
return command;
}
Notes:
in your original parse_command, you allocate memory to command in a loop, which is unnecessary and just creates memory leaks. It is enough to allocate memory once. I assume that you want command to contain n_args + 1 pointers, so I modified the code accordingly.
in the last while loop of parse_command, you increment i incorrectly twice, which also leads to undefined behaviour, i.e. possible segmentation fault. I fixed it here.

Resources