My program runs without error but when I want to free 2D char array (like arguments[0]) it gives me : free(): invalid pointer, fish: Job 1, './a.out' terminated by signal SIGABRT (Abort)
/**
* #brief Parses the input into arguments
*
* EXP:
* "head -n 5 foo.txt"
* arguments[0] = "head"
* arguments[1] = "-n"
* arguments[2] = "5"
* arguments[3] = "foo.txt"
* arguments[4] = NULL
*
* #param input
* #return char**
*/
char** getArguments(char* input, int numOfArgs) {
char copy_arguments[BUFSIZ]; /* To parse input */
strcpy(copy_arguments, input);
char** arguments = calloc(numOfArgs + 1, sizeof(char*));
if (arguments == NULL) {
return NULL;
}
/*allocate memory for arguments depending their length*/
char* argument = NULL;
for (int i = 0; i < numOfArgs; i++) {
if (i == 0) {
argument = strtok(copy_arguments, " ");
} else {
argument = strtok(NULL, " ");
}
int size_of_arg = strlen(argument);
arguments[i] = calloc((size_of_arg + 1), sizeof(char));
strcpy(arguments[i], argument);
}
arguments[numOfArgs + 1] = NULL;
return arguments;
}
int main() {
char **output = getArguments("hello world -n vim", 4);
free(output[0]);
}
The function invokes undefined behavior. There are allocated numOfArgs + 1 pointers
char** arguments = calloc(numOfArgs + 1, sizeof(char*));
So the valid range of indices is [0, numOfArgs].
Thus in this statement
arguments[numOfArgs + 1] = NULL;
there is an access to memory outside the allocated array.
Instead you have to write
arguments[numOfArgs] = NULL;
In general you should check that the returned pointer is not equal to NULL as for example
if ( output ) free(output[0]);
Related
in Main function, calling a function to loop through a text and check if a column already exists. If not add it into an array of string.
Main:
char** departmentList = NULL;
int sizeOfDepartmentList = 0;
departmentList = collectAllDepartments(departmentList, &sizeOfDepartmentList,recordsPtr);
Function loop for a text and check for new elements:
char** collectAllDepartments(char** departmentList, int *sizeOfDepartmentList, char* records){
char* copyOfRecords = malloc(strlen(records)+1);
strcpy(copyOfRecords,records);
char* sav1 = NULL;
char* token = strtok_s(copyOfRecords,"\n",&sav1);
while(token != NULL){
//char *token_orig = _strdup(token);
char* sav2 = NULL;
char* innerToken = strtok_s(token,",",&sav2);
int counter = 1;
while(innerToken != NULL){
if(counter == 4){
if(!departmentExists(departmentList,*sizeOfDepartmentList,innerToken)){
departmentList = addDepartment(departmentList,&sizeOfDepartmentList,innerToken);
}
// allDepartments = (char*) realloc(allDepartments,strlen(innerToken) + strlen(allDepartments));
// strcat(allDepartments,innerToken);
// strcat(allDepartments,",");
}
++counter;
innerToken = strtok_s(NULL, ",", &sav2);
}
token = strtok_s(NULL, "\n", &sav1);
//free(token_orig);
}
free(copyOfRecords);
return departmentList;
}
The function that pushback new elements into the array of string:
char** addDepartment(char** deparmentList, int* sizeOfDepartmentList, char* department){
*sizeOfDepartmentList += 1;
deparmentList = realloc(deparmentList, *sizeOfDepartmentList * sizeof(char *));
deparmentList[*sizeOfDepartmentList - 1] = department;
return deparmentList;
}
The int need to be passed by pointer twice in order to be used in the pushback function. But the compiler complaint receiving pointer of pointer instead of pointer:
My code for creating a StringBundle object is below but essentially i am supposed to place delimiter seperated strings into a dynamically allocated array. My method prints the correct token values for a whole line, but i am not sure why my return value is of incompatable type. below is the struct definition for a StringBundle object. and here is some sample output from my function reading one delimiter-seperated line.
0 901051
1 Becker
2 Locale
3 NM
4 35
5 Eddy
6 015
7 322833N
8 1040812W
9 32.4759521
10 -104.1366141
11
12
13
14
15 959
16 3146
17 Carlsbad East
18 11/01/1992
19
/** A StringBundle contains an array of nTokens pointers to properly-
* terminated C strings (char arrays).
*
* A StringBundle is said to be proper if:
* -Tokens == NULL and nTokens == 0
* or
* -nTokens > 0 and Tokens points to an array of nTokens char pointers,
* -each char pointer points to a char array of minimum size to hold
* its string, including the terminator (no wasted space)
*/
struct _StringBundle {
char** Tokens; // pointer to dynamically-allocated array of char*
uint32_t nTokens; // dimension of array pointed to by Tokens
};
typedef struct _StringBundle StringBundle;
StringBundle* createStringBundle(const char* const str) {
char *token, *string, *tofree, *fin, *arr;
char *strs[20];
tofree = string = strdup(str);
int i = 0;
while ((token = strsep(&string, "|")) != NULL) {
printf("token = %s\n", token);
strs[i] = malloc(strlen(token) + 1);
strcpy(strs[i], token);
//(fin, token);
i++;
}
free(tofree);
return strs;
}
This function is supposed to return a pointer to a StringBundle structure, not an array of strings.
That structure needs to contain a dynamically-allocated array of strings. You grow the array using realloc()
StringBundle* createStringBundle(const char* const str) {
char *token, *string, *tofree, *fin, *arr;
StringBundle *bundle = malloc(sizeof StringBundle);
bundle->Tokens = NULL;
bundle->nTokens = 0;
tofree = string = strdup(str);
while ((token = strsep(&string, "|")) != NULL) {
printf("token = %s\n", token);
bundle->nTokens++;
bundle *temp = realloc(bundle->Tokens, bundle->nTokens * sizeof StringBundle);
if (temp) {
bundle->Tokens = temp;
} else {
printf("realloc error\n");
break;
}
bundle->Tokens[bundle->nTokens-1] = strdup(token);
}
free(tofree);
return bundle;
}
In addition to #Barmar's answer, if you want to avoid the repeated memory reallocation I suggest to go with a 2-pass approach. Pass 1, determine the number of tokens, pass 2, allocate and fill the struct.
You have to strdup the source for each pass since strsep is destructive.
StringBundle* createStringBundle(const char *str,const char *sep)
{
char *token, *dup;
StringBundle *bundle = malloc(sizeof StringBundle);
bundle->Tokens = NULL;
bundle->nTokens = 0;
// pass 1: get the token count
dup = strdup(str);
while (strsep(&dup, sep)) != NULL) bundle->nTokens++;
free(dup);
// pass 2: fill the struct
bundle->Tokens = malloc(bundle->nTokens * sizeof(char*));
bundle->nTokens = 0;
dup = strdup(str);
while ((token = strsep(&dup, sep)) != NULL)
{
bundle->Tokens[bundle->nTokens++] = strdup(token);
}
free(dup);
return bundle;
}
Of course malloc might return NULL. You want to add the error handling yourself.
For some reason, when I realloc an array to append an item to the array, it only works twice before segfaulting. The segfault occurs when I try to print the strings inside of the array. I currently have an array which is NULL terminated.
void apparr(char** arr, char* line) {
int length = 0;
// find the length of the array
while(arr[length] != NULL) {
length++;
}
// realloc with 2 extra spaces (1 for line, 1 for NULL)
arr = realloc(arr, sizeof(char*) * (length+2));
// set last element (which was NULL) to line
arr[length] = line;
// set the NULL terminator
arr[length+1] = NULL;
}
I have no clue where I could be going wrong here, my only guess would be with how I am calling realloc. However, I would understand that not working for 1 resize, but I have no clue why this works for two resizes then segfaults when I am printing back the array.
How it could be used in main:
int main(int argc, char** argv){
char** hist = malloc(sizeof(char**));
char* linep1;
char* linep2;
char* linep3;
char* linep4;
linep1 = (char*)malloc(strlen("test")*sizeof(char));
linep2 = (char*)malloc(strlen("test2")*sizeof(char));
linep3 = (char*)malloc(strlen("test3")*sizeof(char));
linep4 = (char*)malloc(strlen("test4")*sizeof(char));
strcpy(linep1, "test");
strcpy(linep2, "test2");
strcpy(linep3, "test3");
strcpy(linep4, "test4");
apphist(hist, linep1);
apphist(hist, linep2);
//apphist(hist, linep3); //uncommenting this line causes nothing to be printed
//apphist(hist, linep4); //uncommenting this line causes only test4 to be printed
int x = 0;
while (hist[x] != NULL) {
printf("%s\n", hist[x]);
x++;
}
}
In the main function you need to set the first element of hist as NULL as you are checking it in the function apphist
char** hist = malloc(sizeof(char*));
*hist = NULL;
The function apphist only changes the value of arr locally. To reflect the changes in the main function, you need to pass a pointer to a arr i.e. a 3D pointer char ***arr
You should always check the result of realloc and perform actions on failure.
Code for the function is below.
void apparr(char*** arr2, char* line) {
int length = 0;
char **arr = *arr2;
while(arr[length] != NULL) {
length++;
}
arr = realloc(arr, sizeof(char*) * (length+2));
if (arr == NULL) {
exit(1); // handle error
}
*arr2 = arr;
arr[length] = line;
arr[length+1] = NULL;
}
Alternatively, you can return a pointer to a pointer to char and update the value in main.
char** apparr(char** arr, char* line) {
int length = 0;
char **temp;
while(arr[length] != NULL) {
length++;
}
temp = realloc(arr, sizeof(char*) * (length+2));
if (temp == NULL) {
exit(1); // handle error
}
arr = temp;
arr[length] = line;
arr[length+1] = NULL;
return (arr);
}
//in main
hist = apphist(hist, linep1);
hist = apphist(hist, linep2);
I think you should dereference the arr before you use in realloc. Another observation; the sizeof(char*) is usually 4 in 32 bit architecture and 8 in 64 bit instead of 1.
For the general case I think you only need to call realloc with length +1
arr = realloc(arr, sizeof(char*) * (length+1));
This is because you already had space for the NULL terminating pointer from the prior state. With the code you are proposing what's happening is something like this
// state prior to realloc
String String NULL
// apparr() call
String String NULL undefined undefined // realloc
String String String undefined undefined // arr[length] = line;
String String String NULL undefined // arr[length+1] = NULL;
The first time it will work (leaving a dangling allocated node at the end) but the second time it can crash in multiple ways due to the extra allocation.
All errors and may pitfalls have been mentioned by others already.
Below find a more general implementation of the append-element-to-array function:
#include <stdlib.h>
#include <errno.h> /* for EINVAL */
int apparr(char *** parr, char * line) {
size_t length = 0;
if (NULL == *parr) {
if (NULL != line) {
errno = EINVAL;
return -1;
}
} else {
// find the length of the array
while (NULL != (*parr)[length]) {
++length;
}
}
{
// realloc with 2 extra spaces (1 for line, 1 for NULL)
void * pv = realloc(*parr, (length+1) * sizeof **parr);
if (NULL == pv) {
return -1; /* By convention -1 indicates failure. */
}
*parr = pv;
}
(*parr)[length] = line;
if (0 < length) {
(*parr)[length + 1] = NULL;
}
return 0; /* By convention 0 indicates success. */
}
And use it like this:
#include <stdlib.h>
#include <stdio.h>
int apparr(char *** parr, char * line) {
int main(int argc, char** argv) {
char ** hist = NULL;
char * linep1;
char * linep2;
char * linep3;
char * linep4;
if (-1 == apparr(&hist, NULL)) {
perror("apphist() failed initially\n");
exit(EXIT_FAILURE);
}
linep1 = malloc(strlen("test") + 1);
linep2 = malloc(strlen("test2") + 1); /* +1 for the c-string's 0-termination; sizeof (char) is 1 by definition */
linep3 = malloc(strlen("test3") + 1);
linep4 = malloc(strlen("test4") + 1);
strcpy(linep1, "test");
strcpy(linep2, "test2");
strcpy(linep3, "test3");
strcpy(linep4, "test4");
if (-1 == apphist(&hist, linep1)) {
perror("apphist() failed for line 1\n");
exit(EXIT_FAILURE);
}
if (-1 == apphist(&hist, linep2) {
perror("apphist() failed for line 2\n");
exit(EXIT_FAILURE);
}
if (-1 == apphist(&hist, linep3) {
perror("apphist() failed for line 3\n");
exit(EXIT_FAILURE);
}
if (-1 == apphist(&hist, linep4) {
perror("apphist() failed for line 4\n");
exit(EXIT_FAILURE);
}
{
size_t x = 0;
while (hist[x] != NULL) {
printf("%s\n", hist[x]);
++x;
}
}
}
You have several errors in your code:
This is your main error. You don't replace the value in the given pointer. It's correct to use a pointer to the pointer, but you need to dereference it. For this you need to pass the pointer to hist and dereference it at the re-allocation:
*arr = realloc(*arr, sizeof(char*) * (length + 2));
The list of pointers is not initialized, after the first allocation you need to set the first pointer:
hist[0] = NULL;
The allocations for your test strings are 1 off:
linep1 = malloc((strlen("test") + 1) * sizeof(char));
linep2 = malloc((strlen("test2") + 1) * sizeof(char));
linep3 = malloc((strlen("test3") + 1) * sizeof(char));
linep4 = malloc((strlen("test4") + 1) * sizeof(char));
Additional notes:
The includes are missing for a complete minimal reproducable example.
The name apparr() is wrong, you call apphist() in main().
Check the return values of any allocation for NULL, meaning that the allocation failed.
You don't use argc and argv, so write int main(void)
The first allocation has the "wrong" type, but both are pointers, so it's the same size: char** hist = malloc(sizeof(char*));
There is no need to cast pointers returned by malloc() as it returns a pointer to void. Pointers to void and other pointers can be assigned back and forth without casts.
You can replace the malloc()/strcpy() pairs with strdup().
You can even call apphist() with the string as "immediate" value like this: apphist(hist, "test");
main() should return an int, EXIT_SUCCESS is the right value.
You can put some const at the parameters and declarations to make things safer. But think about what is constant.
I'm learning C after graduation and trying to refresh old skills. I'm currently trying to make a dynamically allocated array that consist of dynamically allocated strings. Below is my code, I am trying to add an adjective to previously initialized array that has the first member as NULL. The last member should always be NULL.
char **addAdjective(char **array, const char *adjective)
{
int i = 0;
int count = 0;
while (*array != NULL){
array++;
count += 1;
}
array = (char**) realloc(*array, sizeof(*array) * (count+2));
int adjectiveLength = strlen(adjective);
array[count] = (char*) malloc(sizeof(const char)*(adjectiveLength + 1));
for (i = 0; i < adjectiveLength; i++){
array[count][i] = adjective[i];
}
array[count][i+1] = '\0';
array[count+1] = NULL;
return array;
}
When I'm calling the above with:
adjectives = addAdjective(adjectives, "beautiful");
adjectives = addAdjective(adjectives, "ugly");
adjectives = addAdjective(adjectives, "sweet");
There seems to be something wrong as when I'm trying to print the array I get nothing..
What could be wrong?
EDIT:
Print function should be okay:
void printAdjectives(char **adjectives)
{
if (!adjectives)
return;
while (*adjectives) {
printf("%s ", *adjectives);
adjectives++;
}
printf("\n");
}
And initialization:
char **initAdjectives(void)
{
char **adjectives = (char **)malloc (1 * sizeof(char *));
*adjectives = NULL;
return adjectives;
}
array[count][i+1] = '\0';
ought to be
array[count][i] = '\0';
Or better
array[count][adjectiveLength] = '\0';
Notice that when the code reaches that line i==adjectiveLength.
You allocated adjectiveLength+1 characters and writing to i+1 is past the end of the allocated space.
I don't know if that's your only error but it is illegal.
I have string array initialized like that:
char ** strArray;
if ( (strArray = malloc(sizeof(*strArray) + 3)) == NULL ) {
fprintf(stderr, "ls1: couldn't allocate memory");
//exit(EXIT_FAILURE);
}
strArray[0] = NULL;
strArray[0] = "111";
strArray[1] = "222";
strArray[2] = "1";
strArray[3] = "2";
I want to convert this string array to int array, like that:
int * toIntArray(char ** strArray) {
int size = getCharArraySize(strArray);
int intArray[size];
int i;
for ( i = 0; i < size ; ++i)
{
intArray[i] = atoi(strArray[i]);
printf( "r[%d] = %d\n", i, intArray[i]);
}
intArray[size] = '\0';
return intArray;
}
int getCharArraySize(char ** strArray) {
int s = 0;
while ( strArray[s]) {
printf("Char array: %s.\n", strArray[s]);
s++;
}
return s;
}
And then I want to sort this int array.
I must have string array initilized like above (char ** strArray) and then convert this to int array and then sort it. Can anybody help my with that? I would ask about printed sorted integer in main function.
A few minor things to take note of in the question code:
char ** strArray;
if ( (strArray = malloc(sizeof(*strArray) + 3)) == NULL ) {
fprintf(stderr, "ls1: couldn't allocate memory");
//exit(EXIT_FAILURE);
}
If successful, the intention of the above code allocates memory to strArray sufficient for three char *'s. Specifically, strArray[0], strArray1 and strArray[2].
NOTE: As pointed out in Matt McNabb's comment below, it actually incorrectly allocates memory sufficient for one char *, and three extra bytes.
strArray[0] = NULL;
The above line sets sets the first pointer in the **strArray to point at NULL.
strArray[0] = "111";
The above code is odd. After just setting strArray[0] to point at NULL, the above line changes it to point to "111". Kind of makes setting it to NULL (in the first place) seem unnecessary.
strArray[1] = "222";
strArray[2] = "1";
The above two lines initialize the other two pointers in the strArray correctly.
strArray[3] = "2";
The above line attempts to initialize strArray[3], when that element of the array really doesn't exist. So, it is changing something to point to "2", but probably not with the expected result.
Perhaps the intent would be better served by changing the above code to:
char **strArray;
size_t strArrayElements=4;
if(NULL == (strArray = malloc((strArrayElements+1) * sizeof(*strArray))))
{
fprintf(stderr, "ls1: couldn't allocate memory");
exit(EXIT_FAILURE);
}
strArray[strArrayElements] = NULL;
strArray[0] = "111";
strArray[1] = "222";
strArray[2] = "1";
strArray[3] = "2";
As can be observed, the above code allocates 5 elements (strArrayElements+1) to the **strArray. The last element strArray[4] is initialized to NULL; a marker to indicate End-Of-List. Then the other 4 elements [0..3] are initialized.
Now shifting focus to:
int * toIntArray(char ** strArray) {
int size = getCharArraySize(strArray);
int intArray[size];
int i;
for ( i = 0; i < size ; ++i)
{
intArray[i] = atoi(strArray[i]);
printf( "r[%d] = %d\n", i, intArray[i]);
}
intArray[size] = '\0';
return intArray;
}
The above code is successful at converting the strings to their integer forms, and storing them in intArray. However, the code is flawed when it attempts to return intArray to the caller. The intArray variable was declared as a local stack object. The return statement causes all such stack variables to become invalid; and allows the stack memory such variables were using to be used for other things.
Perhaps the the following code better represents what was intended. It allocates memory from the heap for intArray. This allocated memory can outlive the return statement:
int *toIntArray(char **strArray)
{
int size = getCharArraySize(strArray);
int *intArray = malloc(size * sizeof(*intArray));
int i;
for ( i = 0; i < size ; ++i)
{
intArray[i] = atoi(strArray[i]);
printf( "r[%d] = %d\n", i, intArray[i]);
}
intArray[size] = '\0';
return(intArray);
}
Spoiler code may be found here.