I am trying to return an array of string from a function and then free the memory it used. The code is below:
int main(int argc, const char * argv[])
{
for (int m = 0; m < 10000; m++) {
char **data = dataTest();
int i = 0;
while(data[i]) {
printf("%p ",data[i]);
free(data[i]);
i++;
}
printf(" address= %p.\n",data);
free(data);
}
return 0;
}
Here is the function:
char **dataTest()
{
char *row[] = {"this", "is", "a", "data", "string", NULL};
char **str = row;
char **dataReturn = (char **) malloc(sizeof(char *) * 6);
int i = 0;
while (*str) {
dataReturn[i] = malloc(sizeof(char) * strlen(*str));
strcpy(dataReturn[i++], *str);
str++;
}
return dataReturn;
}
It runs well in the beginning, but soon the error occurs. Below is the result. The address goes wrong somehow and the malloc error happens. Anyone has met the same problem before?
0x100300030 0x100300040 0x100300050 0x100300060 0x100300070 address= 0x100300000.
0x100300030 0x100300040 0x100300050 0x100300060 0x100300070 address= 0x100300000.
0x100400030 0x100300030 0x100300040 0x100300050 0x100300060 address= 0x100400000.
testC(562,0x7fff73e71310) malloc: *** error for object 0x3000000000000:
pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
0x100300060 0x100300070 0x100300030 0x100300040 0x100300050 0x3000000000000
Program ended with exit code: 9
You need to add this to just before return dataReturn; in your dataTest function:
dataReturn[i] = NULL ;
otherwise your while (data[i]) {} will continue further than wanted.
And instead of:
dataReturn[i] = malloc( sizeof(char) * (strlen(*str)) );
write:
dataReturn[i] = malloc(strlen(*str) + 1);
in order to allocate space for the terminating zero.
BTW sizeof (char) is always 1.
Related
So I'm currently trying to write a C program to track the longest word(s) from argv.
It's been going great! Until I tried to reallocate a character double pointer, it seems to think it's an invalid pointer.
The exact error I'm getting is;
realloc(): invalid pointer
fish: Job 1, './longest-strings.o hello...' terminated by signal SIGABRT (Abort)
I'm creating this double character pointer through the return of a function, is this possibly the error? I'm pretty sure my use of realloc is correct, and I can't quite seem to trace the issue.
Any help would be massively appreciated!
/*
* Author: Smallblue2
* Description: Program finds the longest word in an input string
*
* Input: A string from cmd line
* Output: The longest word in a string
*/
// Header files
#include <stdio.h>
#include <stdlib.h>
// Function prototypes
int stringLength(char *string);
void longestWords(char **strings, int amt);
char **reset(char *string);
void display(char **longest, int len_array);
// Main function
int main(int argc, char **argv)
{
char **strings = &*(argv + 1);
longestWords(strings, argc - 1);
return 0;
}
// Find the length of a string
int stringLength(char *string)
{
int length = 0;
while (*string != '\0')
{
length++;
string++;
}
return length;
}
// Finds the longest word(s) from argv
void longestWords(char **strings, int amt)
{
// Set up variables & pointers
int len_array = 1;
// Assign the first string to be the longest
char **longest = reset(*(strings));
int longest_len = stringLength(*(longest));
int length = 0;
// Loop through the rest of the strings
for (int i = 1; i < amt; i++)
{
// Find the length of the current string
length = stringLength(*(strings + i));
// If it is larger, reset the longest array and place the
// new string inside
if (length > longest_len)
{
longest_len = length;
longest = reset(*(strings + i));
len_array = 1;
// Else, expand the longest array's memory and add the
// additional string inside
} else if (length == longest_len) {
len_array++;
char **temp_longest = (char **)realloc(longest, len_array * sizeof(char *));
if (!longest)
{
printf("Error: Memory allocation failed!\n");
free(longest);
return;
}
longest = temp_longest;
*(longest + len_array - 1) = *(strings + i);
}
}
// Display the longest word(s)
display(longest, len_array);
free(longest);
longest = NULL;
return;
}
// Resets the longest word array
char **reset(char *string)
{
char **longest = (char **)malloc(sizeof(char *));
if (!longest)
{
printf("Error: Memory Allocation Failed!\n");
return NULL;
}
longest = &string;
return longest;
}
// Displays the longest word(s)
void display(char **longest, int len_array)
{
for (int i = 0; i < len_array; i++)
{
printf("%s\n", *(longest + i));
}
return;
}
I've tried to use both calloc and malloc, I tried executing the script where realloc wouldn't occur and then apparently free() believes there's an invalid pointer too. Really lost here.
Here are the two minimal changes:
stringLength should handle a NULL pointer.
int stringLength(char *string)
{
int length = 0;
while (string && *string != '\0')
{
length++;
string++;
}
return length;
}
Or perhaps:
#include <string.h>
size_t stringLength(char *string)
{
return string ? strlen(string) : 0;
}
reset() leaks the memory you just allocated, and you don't want to take the address of an argument which is out of scope when the function returns. Not entirely sure what the point of the function is but try this instead:
char **reset(char *string)
{
char **longest = malloc(sizeof(char *));
if (!longest)
{
printf("Error: Memory Allocation Failed!\n");
return NULL;
}
*longest = string;
return longest;
}
and example output:
$ ./a.out hello...
hello...
./a.out hello world!
world!
is that even possible?
Let's say that I want to return an array of two characters
char arr[2];
arr[0] = 'c';
arr[1] = 'a';
from a function. What type do I even use for the function? Is my only choice to use pointers and void the function? So far I've tried having a char* function or a char[]. Apparently you can only have functions of char(*[]). The only reason I want to avoid using pointers is the fact that the function has to end when it encounters a "return something;" because the value of "something" is a character array (not a string!) that might change size depending on the values I pass into the function through the main function. Thanks to anyone who responds in advance.
You've got several options:
1) Allocate your array on the heap using malloc(), and return a pointer to it. You'll also need to keep track of the length yourself:
void give_me_some_chars(char **arr, size_t *arr_len)
{
/* This function knows the array will be of length 2 */
char *result = malloc(2);
if (result) {
result[0] = 'c';
result[1] = 'a';
}
/* Set output parameters */
*arr = result;
*arr_len = 2;
}
void test(void)
{
char *ar;
size_t ar_len;
int i;
give_me_some_chars(&ar, &ar_len);
if (ar) {
printf("Array:\n");
for (i=0; i<ar_len; i++) {
printf(" [%d] = %c\n", i, ar[i]);
}
free(ar);
}
}
2) Allocate space for the array on the stack of the caller, and let the called function populate it:
#define ARRAY_LEN(x) (sizeof(x) / sizeof(x[0]))
/* Returns the number of items populated, or -1 if not enough space */
int give_me_some_chars(char *arr, int arr_len)
{
if (arr_len < 2)
return -1;
arr[0] = 'c';
arr[1] = 'a';
return 2;
}
void test(void)
{
char ar[2];
int num_items;
num_items = give_me_some_chars(ar, ARRAY_LEN(ar));
printf("Array:\n");
for (i=0; i<num_items; i++) {
printf(" [%d] = %c\n", i, ar[i]);
}
}
DO NOT TRY TO DO THIS
char* bad_bad_bad_bad(void)
{
char result[2]; /* This is allocated on the stack of this function
and is no longer valid after this function returns */
result[0] = 'c';
result[1] = 'a';
return result; /* BAD! */
}
void test(void)
{
char *arr = bad_bad_bad_bad();
/* arr is an invalid pointer! */
}
Since you have a predetermined size of you array you can in-fact return the array if you wrap it with a struct:
struct wrap
{
char a[2] ;
} ;
struct wrap Get( void )
{
struct wrap w = { 0 } ;
w.a[0] = 'c';
w.a[1] = 'a';
return w ;
}
You can return a pointer for the array from a function, however you can't return pointers to local arrays, the reference will be lost.
So you have 3 options:
Use a global variable:
char arr[2];
char * my_func(void){
arr[0] = 'c';
arr[1] = 'a';
return arr;
}
Use dynamic allocation (the caller will have the responsibility to free the pointer after using it; make that clear in your documentation)
char * my_func(void){
char *arr;
arr = malloc(2);
arr[0] = 'c';
arr[1] = 'a';
return arr;
}
Make the caller allocate the array and use it as a reference (my recommendation)
void my_func(char * arr){
arr[0] = 'c';
arr[1] = 'a';
}
If you really need the function to return the array, you can return the same reference as:
char * my_func(char * arr){
arr[0] = 'c';
arr[1] = 'a';
return arr;
}
You can pass the array to the function and let the function modify it, like this
void function(char *array)
{
array[0] = 'c';
array[1] = 'a';
}
and then
char array[2];
function(array);
printf("%c%c\n", array[0], array[1]);
If you want it as a return value, you should use dynamic memroy allocation,
char *function(void)
{
char *array;
array = malloc(2);
if (array == NULL)
return NULL;
array[0] = 'c';
array[1] = 'a';
return array;
}
then
char *array = function();
printf("%c%c\n", array[0], array[1]);
/* done using `array' so free it because you `malloc'ed it*/
free(array);
Important Note:
You should be aware of the fact that the array as filled above is not a string, so you can't for instance do this
printf("%s\n", array);
because the "%s" expects a matching string to be passed, and in c an array is not a string unless it's last character is '\0', so for a 2 character string you need to allocate space for 3 characters and set the last one to '\0'.
char* getCharArray()
{
return "ca";
}
This works perfecly:
int comm_read_data(int file_i2c, unsigned char** buffer)
{
*buffer = malloc(BUFFER_SIZE);
if (i2c_read_bytes(file_i2c, *buffer, BUFFER_SIZE) != 0)
{
return -1;
}
return BUFFER_SIZE;
}
And then call the function:
unsigned char* buffer;
int length = comm_read_data(file_i2c, &buffer);
/* parse the buffer here */
free(buffer);
To allocate and free a single string in C, I do the following:
char[10] stringToCopy = "CopyString";
int length = strlen(stringToCopy) + 1;
char* CopiedString = malloc(length);
strcpy(CopiedString, stringToCopy, length);
printf("DatabasePath=%s\r\n", CopiedString);
free(CopiedString);
In my program, I need to copy such strings to a char** datatype. I need help in writing such a program. I am using a third party API which has a structure with this char** field entry.
I am not aware of how to allocate memory to this datatype and then copy the CopiedString into a list of such values. And also how to free the value after usage.
Allocating memory:
char **arr = malloc(r * sizeof(char *));
for (i=0; i<r; i++)
{
arr[i] = malloc(c * sizeof(char));
}
Freeing memory:
for (i=0; i<r; i++)
{
free(arr[i]);
}
free(arr);
I am not aware of how to allocate memory to this datatype ....
Follows is a useful C idiom for allocating.
size_t number_in_array = ...;
ptr = malloc(sizeof *ptr * number_in_array);
if (ptr == NULL) {
puts("Allocation failed");
} else {
puts("Success");
// Use ptr
free(ptr): // **
}
...
free(ptr): // **
// ** free(ptr) in 1 of 2 places.
Notice there is no need to code the type of the pointer in the allocation: ptr = malloc(sizeof *ptr * number_in_array);. This is easier to code right, review and maintain than attempting to code the type.
... then copy the CopiedString into a list of such values.
You already have good code to form a copied string. Make a helper function. Below is OP's with some improvements. Also research the common strdup() function.
char *my_strdup(const char *stringToCopy) {
size_t size = strlen(stringToCopy) + 1;
char* CopiedString = malloc(size);
if (CopiedString) {
memcpy(CopiedString, stringToCopy, size);
}
return CopiedString;
}
And also how to free the value after usage.
size_t number_in_array = 3;
char **ptr = malloc(sizeof *ptr * number_in_array);
if (ptr == NULL) {
puts("Allocation failed");
} else {
ptr[0] = my_strdup("Hello");
ptr[1] = my_strdup(" ");
ptr[2] = my_strdup("World");
// Use ptr (could check for ptr[] allocation failures first)
for (size_t i = 0; i < number_in_array; i++) {
free(ptr[i]);
}
free(ptr):
}
You can use strdup to create malloced string in c.
char ** presult = NULL;
for double pointer "presult" we can assign data like this.
if (presult) {
*presult = strdup("CopyString");
}
Sample code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int copy_data(char ** p) {
if (p) {
*p = strdup("Test data");
}
return 0;
}
int main () {
char * p = NULL;
copy_data(&p);
if (p) {
printf("daat : %s\n", p);
// free if not used
free(p);
p = NULL;
}
return 0;
}
Go through the below program which explains how to allocate memory for char** and also how to free the same.
Comments are in lined for understanding, please get back in case of any clarification needed.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define NUMBER_OF_STRINGS 5
#define MAX_LEN_OF_STRING 50
void printStrings_array(char ex_strings[][MAX_LEN_OF_STRING], int nstrings);
char** allocMemForStrings(int nStrings);
void printStrings_ptr(char** strings, int nStrings);
int main()
{
// example list of string for which we are going to allocate memory and store in char**
char ex_strings[NUMBER_OF_STRINGS][MAX_LEN_OF_STRING] =
{
"This is the First String",
"This is the Second String",
"This is the Third String",
"This is the Fourth String",
"This is the Fifth String",
};
printf("contents of char[][] \n");
printStrings_array(ex_strings, NUMBER_OF_STRINGS);
// list_of_strings is a variable which points to list of strings
char** list_of_strings = NULL;
// allocating memory for list of strings
if ( list_of_strings = allocMemForStrings(NUMBER_OF_STRINGS))
{
int i = 0;
printf("got %p for list_of_strings\n", (void*)list_of_strings);
while(i < NUMBER_OF_STRINGS)
{
size_t len = strlen(ex_strings[i])+1;
// allocate memory for each string as per its length
list_of_strings[i] = malloc(len);
printf("got %p for string %d\n", (void*)list_of_strings[i], i);
memset(list_of_strings[i], 0, len);
strncpy(list_of_strings[i], ex_strings[i], len);
i++;
}
printf("contents of char** \n");
printStrings_ptr(list_of_strings, NUMBER_OF_STRINGS);
// free ing the memory for char **
// first we need to free the memory for each of the strings pointed by the list_of_strings variable.
i = 0;
while(i < NUMBER_OF_STRINGS)
{
printf("\n freeing %p ", (void*)list_of_strings[i]);
free(list_of_strings[i]);
list_of_strings[i] = NULL;
i++;
}
//now free the list_of_strings pointer
printf("\n finally freeing %p ", (void*)list_of_strings);
free(list_of_strings);
// to avoid dangling pointers, its best practice to set the pointers = NULL after free.
list_of_strings = NULL;
}
else
{
printf("cannot allocate memory for strings\n");
}
return 0;
}
void printStrings_array(char ex_strings[][MAX_LEN_OF_STRING], int nstrings)
{
for(int i = 0; i< nstrings;i++)
printf(" %s\n", ex_strings[i]);
}
void printStrings_ptr(char** strings, int nStrings)
{
for(int i = 0; i< nStrings;i++)
printf(" %s\n", strings[i]);
}
char** allocMemForStrings(int nStrings)
{
// need to have memory to store nStrings
return malloc(nStrings * sizeof (char*));
}
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void sortString(const char* input, char* output);
int cmpstr(void const *a,void const *b);
int readAllWords(FILE* f, char*** res, int * num_read);
int main (int argc, char ** argv)
{
char **wordList;
FILE* fid;
int numWords;
fid = fopen(argv[1],"r");
readAllWords(fid, &wordList,&numWords);
}
int readAllWords(FILE* f, char*** res, int * num_read)
{
char buffer[128];
*num_read = 0;
int size;
while(fgets(buffer,128,f))
{
*num_read = *num_read +1;
size = strlen(buffer);
res = (char***)malloc(sizeof(char**));
*res = (char **)realloc(*res,sizeof(char*)*(*num_read));
(*res)[(*num_read)-1] = (char *)realloc((*res)[(*num_read)-1],sizeof(char)*size);
strcpy((*res)[(*num_read)-1],buffer);
printf("%s\n",(*res)[(*num_read)-1]);
}
printf("%s\n",(*res)[0]);
}
The values are storing and it prints out inside the while loop. But after the while loop, it cannot print out the strings.
The File is given in the main function. Do not understand why realloc is causing the loss of data?
One problem is that the code doesn't initialize res in main(), so you attempt to realloc() an indeterminate value. Either NULL or a value previously returned by malloc() or realloc() (or calloc()) would be OK, but since you pass an indeterminate value, you are invoking undefined behaviour, and a crash is a valid response to doing that.
However, there's a lot of other code in the function that should be reviewed as well.
This code works, and gets a clean bill of health from valgrind.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void readAllLines(FILE *f, char ***res, int *num_read);
int main(int argc, char **argv)
{
char **wordList = 0;
FILE *fid;
int numLines = 0;
if (argc > 1 && (fid = fopen(argv[1], "r")) != 0)
{
readAllLines(fid, &wordList, &numLines);
fclose(fid);
for (int i = 0; i < numLines; i++)
printf("%d: %s", i, wordList[i]);
for (int i = 0; i < numLines; i++)
free(wordList[i]);
free(wordList);
}
return 0;
}
void readAllLines(FILE *f, char ***res, int *num_read)
{
char buffer[128];
int size;
while (fgets(buffer, sizeof(buffer), f))
{
*num_read = *num_read + 1;
size = strlen(buffer) + 1;
char **space = (char **)realloc(*res, sizeof(char *) * (*num_read));
if (space == 0)
return;
*res = space;
(*res)[*num_read - 1] = (char *)malloc(sizeof(char) * size);
if ((*res)[*num_read - 1] == 0)
return;
strcpy((*res)[*num_read - 1], buffer);
printf("%s\n", (*res)[*num_read - 1]);
}
printf("%s\n", (*res)[0]);
}
Possible reason for a segmentation fault:
res = (char***)malloc(sizeof(char**));
*res = (char **)realloc(*res,sizeof(char*)*(*num_read));
In the second line you try to reallocate whatever *res is pointing to. However since you did not initialize *res this could be anything. This will work only if *res == NULL. I guess it should be malloc, not realloc.
Other problems:
You allocate everything new in each loop iteration. This is a huge memory leak.
You already pass a valid memory address pointing to an char** by res, you shouldn't allocate for it again. It is an out parameter. (Remove the malloc call)
You need an initial malloc for *res before the loop (Or set *res = NULL).
The second realloc for *res[...] should be a malloc, because you never actually reallocate here. Also instead of allocating size bytes, you should allocate size+1 bytes for the terminating \0.
Your function has no return statement although it is non-void.
Below is some psudo, but I'm trying to accomplish this. The problem is as written, it returns a blank pointer.
int testFunction(char *t) {
int size = 100;
t = malloc(100 + 1);
t = <do a bunch of stuff to assign a value>;
return size;
}
int runIt() {
char *str = 0;
int str_size = 0;
str_size = testFunction(str);
<at this point, str is blank and unmodified, what's wrong?>
free(str);
return 0;
}
This works fine if I have a predefined size, such as char str[100] = "" and I don't try to malloc or free memory afterwords. I need to be able to make the size dynamic though.
I've also tried this, but seem to run into a corrupt pointer somehow.
int testFunction(char **t) {
int size = 100;
t = malloc(100 + 1);
t = <do a bunch of stuff to assign a value>;
return size;
}
int runIt() {
char *str = 0;
int str_size = 0;
str_size = testFunction(&str);
<at this point, str is blank and unmodified, what's wrong?>
free(str);
return 0;
}
Thanks!
Your test function is just a bit backward. Size should be an input. The allocated pointer should be the output:
char* testFunction(int size) {
char* p = malloc(size);
<do a bunch of stuff to assign a value>;
return p;
}
int runIt() {
char *str = 0;
int str_size = 100;
str = testFunction(str_size);
<do something>
free(str);
return 0;
}
edit
Per comment, making size an output too.
char* testFunction(int *size) {
*size = <compute size>;
char* p = malloc(size);
<do a bunch of stuff to assign a value>;
return p;
}
int runIt() {
char *str = 0;
int str_size;
str = testFunction(&str_size);
<do something>
free(str);
return 0;
}
You're nearly there with the second example, but change
int testFunction(char **t) {
...
t = malloc(100 + 1);
To
int testFunction(char **t) {
...
*t = malloc(100 + 1);
The point being that you're passing in a char**, a pointer to a pointer, so you want to assign the malloc to what that points at (a pointer).
I am also studying c++. I had a the same question. So after speaking to c++ pro at work, he suggest me to do something like this
int method(char* p) {
if (p) {
strcpy(p, "I like c++");
}
return strlen("I like c++");
}
int main()
{
char* par = NULL;
int len = method(par);
if (len > 0) {
par = (char*)malloc(len+1);
memset(par, 0, len + 1);
method(par);
cout << "ret : " << par;
}
free(par);
}