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.
Related
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]);
I am solving binary tree paths leet code programming question 257. I am having issue for one of the larger input where my code is getting segmentation fault. I suspect that there is an problem with my realloc but I am not able to figure it out.
Below is my approach:
Initially I started by dynamically allocating 80 bytes of memory of type char (80/8 = 10 rows)and storing the returned address to char **res variable.
char ** res = (char **)malloc(sizeof(char *) * sum);
I am calling findpath function recursively to find all the binary tree paths. Whenever one path is found , I dynamic allocate 100 bytes for each row index.
res[resIdx] = (char *)malloc(sizeof(char) * 100);
I have one global variable resIdx which points to the current row index where I copy the found binary tree path and increment the global variable resIdx.
if the resIdx becomes greater then total number of rows which was previously allocated then I do realloc of the memory but it looks like realloc is getting failed.
if (resIdx >= sum)
{
sum = sum + 10;
res = (char **)realloc(res,sizeof(char *) * sum); //Any issue here?
}
Can anyone please help me to figure out what's wrong I am doing in my code. Below is my full code
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int sum;
int resIdx;
void findpath (struct TreeNode* root, int *ls,int ls_idx,char **res);
char ** binaryTreePaths(struct TreeNode* root, int* returnSize){
if (root == NULL)
{
*returnSize = 0;
return NULL;
}
resIdx = 0;
sum = 10;
char ** res = (char **)malloc(sizeof(char *) * sum);
int ls[100];
findpath(root,&ls[0],0,res);
*returnSize = resIdx;
return &res[0];
}
void findpath (struct TreeNode* root, int *ls,int ls_idx,char **res)
{
char temp[100];
int l=0,i=0;
if (root->left == NULL && root->right == NULL)
{
ls[ls_idx] = root->val;
ls_idx+=1;
if (resIdx >= sum)
{
sum = sum + 10;
res = (char **)realloc(res,sizeof(char *) * sum);
}
res[resIdx] = (char *)malloc(sizeof(char) * 100);
while (i < ls_idx)
{
if (i==0)
{
l = l + sprintf(&temp[l], "%d", ls[i]);
}
else
{
l = l + sprintf(&temp[l], "->%d", ls[i]);
}
i++;
}
strcpy(res[resIdx],temp);
resIdx++;
return;
}
ls[ls_idx] = root->val;
if (root->left != NULL)
{
findpath(root->left,ls,ls_idx+1,res);
}
if (root->right != NULL)
{
findpath(root->right,ls,ls_idx+1,res);
}
return;
}
The last argument to your findPath function is declared as a char** type; thus, when you make the call findpath(root,&ls[0],0,res); in binaryTreePaths, where the res variable is a char** type, a copy of that pointer is passed to the findPath function (most likely, but not necessarily, by placing that copy on the stack).
Then, if reallocation is required, the res = (char **)realloc(res,sizeof(char *) * sum); line in that function overwrites the value in the passed copy and, at the same time (if the call is successful – vide infra), will (probably) invalidate (i.e. free) the memory referenced by the previous address in that res copy. Thus, when control returns to the calling binaryTreePaths function, its own version of res will not have been modified and will remain pointing to that (now invalid) memory.
So, in order for your findPath function to be able to modify the given res argument, that must be passed as a pointer – in this case, a pointer to a char**, which will be of type char***; then, when called, you will need to pass the address of the res variable in binaryTreePaths.
Note also that directly overwriting a pointer in a call to realloc, as you have done in the line of code quoted above is dangerous. This is because, should that call fail, then you have lost the original data pointer (it will have been overwritten with NULL) and error recovery will be very difficult. You should save the return value in a temporary variable and only replace your original if the call succeeds.
With the code you have provided, I cannot properly test for any other errors but, taking the points above in hand, the below is a possible fix. See also: Do I cast the result of malloc?
int sum;
int resIdx;
void findpath(struct TreeNode* root, int* ls, int ls_idx, char*** res); // Note last argument type!
char** binaryTreePaths(struct TreeNode* root, int* returnSize)
{
if (root == NULL) {
*returnSize = 0;
return NULL;
}
resIdx = 0;
sum = 10;
char** res = malloc(sizeof(char*) * sum);
int ls[100];
findpath(root, &ls[0], 0, &res); // Pass ADDRESS of res
*returnSize = resIdx;
return &res[0];
}
void findpath(struct TreeNode* root, int* ls, int ls_idx, char*** res)
{
char temp[100];
int l = 0, i = 0;
if (root->left == NULL && root->right == NULL) {
ls[ls_idx] = root->val;
ls_idx += 1;
if (resIdx >= sum) {
sum = sum + 10;
char** test = realloc(*res, sizeof(char*) * sum);
if (test == NULL) {
// Handle/signal error
return;
}
*res = test; // Only replace original if realloc succeeded!
}
(*res)[resIdx] = malloc(sizeof(char) * 100);
while (i < ls_idx) {
if (i == 0) {
l = l + sprintf(&temp[l], "%d", ls[i]);
}
else {
l = l + sprintf(&temp[l], "->%d", ls[i]);
}
i++;
}
strcpy((*res)[resIdx], temp);
resIdx++;
return;
}
ls[ls_idx] = root->val;
if (root->left != NULL) {
findpath(root->left, ls, ls_idx + 1, res);
}
if (root->right != NULL) {
findpath(root->right, ls, ls_idx + 1, res);
}
return;
}
I have a function that returns a pointer to pointers of chars (char**). The function takes 2 arguments
int* num_paths: a pointer to an integer to indicate the number of strings to be returned.
int* errno: a pointer to an integer to indicate an error code. This can contain different values, so I cannot simply check if NULL is returned in case of error.
Some example code is written below (with the majority of error checks omitted for simplicity):
char** get_paths(int* num_paths, int* errno) {
char* path1 = NULL;
char* path2 = NULL;
char** paths = NULL;
if(errno == NULL) {
printf("Set errno in case of error, but cannot dereference NULL pointer\n");
goto exit;
}
path1 = calloc(1, strlen("foo") + 1);
path2 = calloc(1, strlen("bar") + 1);
strcpy(path1, "foo");
strcpy(path2, "bar");
*num_paths = 2;
paths = calloc(1, *num_paths*sizeof(char *));
paths[0] = path1;
paths[1] = path2;
*errno = 0;
exit:
return paths;
}
int main(void) {
char** paths = NULL;
int num_paths = 0;
int errno = 0;
paths = get_paths(&num_paths, &errno);
if(errno != 0) {
return -1;
}
for(int i = 0; i < num_paths; i++) {
printf("%s\n", paths[i]);
free(paths[i]);
}
free(paths);
}
The problem I have with this is that I can't set the error code in case a NULL pointer is passed as argument for errno. You could argue that this is a user error, but I would still like to avoid this situation in the first place.
So my question is: can I rewrite my get_paths function such that it returns an integer as error code, but also returns a char** through the function arguments without resorting to char*** like in the following example:
int get_paths_3(char*** paths, int* num_paths) {
char* path1 = NULL;
char* path2 = NULL;
path1 = calloc(1, strlen("foo") + 1);
path2 = calloc(1, strlen("bar") + 1);
strcpy(path1, "foo");
strcpy(path2, "bar");
*num_paths = 2;
*paths = calloc(1, *num_paths*sizeof(char *));
(*paths)[0] = path1;
(*paths)[1] = path2;
return 0;
}
This is pretty much the only case where "three star" pointers are fine to use. It's fairly common practice in API design to reserve the return value for error codes, so this situation isn't uncommon.
There are alternatives, but they are arguably not much better. You could abuse the fact that void* can be converted to/from char** but it isn't much prettier and less type safe:
// not recommended
int get_paths_4 (void** paths, size_t* num_paths)
{
char* path1 = calloc(1, strlen("foo") + 1);
char* path2 = calloc(1, strlen("bar") + 1);
strcpy(path1, "foo");
strcpy(path2, "bar");
*num_paths = 2;
char** path_array;
path_array= calloc(1, *num_paths*sizeof(char *));
path_array[0] = path1;
path_array[1] = path2;
*paths = path_array;
return 0;
}
...
void* vptr;
size_t n;
get_paths_4 (&vptr, &n);
char** paths = vptr;
for(size_t i=0; i<n; i++)
{
puts(paths[i]);
}
A more sound alternative might be wrap all your parameters into a single struct type and pass that one as a pointer.
Unfortunately you cannot mixing return types in C is a terrible mistake and should not be done, you can either:
return the pointer you need and add a error code to a variable
return the error code and add the pointer to a variable
Both are valid strategies and I'd pick the one that matches the rest of your code to have consistency.
I tried many solution for this issue, but none worked properly!
I want to copy value of char** array to a variable of type char*.
char *line;
char **tokens = malloc(....);
So, I tried the following:
for(i=0; i < sizeof(tokens); i++)
strncpy(line, tokens[i], strlen(line));
Or
for(i=0; i < sizeof(tokens); i++)
strncat(line, tokens[i]);
Or
for(i=0; i < sizeof(tokens); i++)
memcpy(line, tokens[i], strlen(line));
My understanding is that tokens[i] would be of type char*, but what I couldn't understand if the error I'm getting.
Segmentation fault (core dumped)
If these ways won't work, how can I do the copying?
Any hints?
char *removesubString(char *path, char **args){
char *dir;
int COUNT;
COUNT = 100;
char **dirs = malloc(sizeof(char*)*COUNT);
int i, position;
for (i = 2; i < sizeof(args); i++) {
if(args[i] == NULL){
break;
}
dir = strtok(path, PATH_DELIM);
position = 0;
while (dir != NULL) {
if(strcmp(dir, args[i]) == 0){
dir = strtok(NULL, PATH_DELIM);
continue;
}
dirs[position] = dir;
position++;
dir = strtok(NULL, PATH_DELIM);
}//end of while
dirs[position] = NULL;
}//end of for
char *line;
line = "";
for (i = 0; i < position; i++) {
strncpy(line, dirs[i], strlen(dirs[i]));
}
return line;
}
The first issue that pops up about your code is that you're wrong with the boundaries:
char *line;
char **tokens = malloc(TOKENS_ARRAY_SIZE);
when you do:
for(i=0; i < sizeof(tokens); i++) {
…
}
it's not returning the size of the allocated memory, but the allocated memory for the tokens pointer itself. From the sizeof manpage:
Returns the size, in bytes, of the object representation of type
It happens that when you do sizeof on a static matrix, it will return the size of the matrix because that's the amount of allocated memory for it. But for a dynamically allocated matrix, it will only return the size of the pointer, i.e. if you do:
char array_static[42];
char* array_dyn = malloc(sizeof(char)*42);
printf("sizeof(array_static) = %d\n", sizeof(array_static));
printf("sizeof(array_dyn) = %d\n", sizeof(array_dyn));
it will return:
sizeof(array_static) = 42
sizeof(array_dyn) = 8
so if the number of items within your dynamic array is less than the returned size of the array's pointer, you'll overflow and you'll get a segfault.
So the right way to handle your situation, is to keep the length of the dynamic array in another variable, update it as you're setting up the size of the allocated memory, and then use that value for iterations.
int tokens_length = 42;
char *line;
char **tokens = malloc(sizeof(char*)*tokens_length);
for(i=0; i < sizeof(tokens_length); i++) {
…
}
so in your case, you should be doing:
// keep somewhere the number of directories that you *can* allocate
int nb_dirs = 100;
char **dirs = malloc(sizeof(char*) * nb_dirs);
…
// keep a pointer on how many directories you've added
int position = 0;
while (dir != NULL) {
…
position++;
// fail loudly if you're adding more directories than you've allocated
// or you might use realloc() to extend the array's length
if (position >= nb_dirs) {
printf("ERROR! Too many directories!");
// RETURN WITH ERROR!
}
…
}
// here you iterate over all the directories you've added
for(i = 0; i <= position; i++){
// here you can do stuff with dirs, and copy only the length of the dirs element
strncpy(<TARGET>, dirs[i], strlen(dirs[i]);
}
Then there's another issue you should think about: in your loop, you're modifying path, given as an argument, where you're strcpy()ing dirs into:
strncpy(path, dirs[i], <LENGTH>);
But that makes little sense, whatever you're trying to do is not what you've written.
Here, considering that the size argument is correctly set, you'd be copying each item of the dirs array into the same variable. So you'd end up having always the last value of the dirs array referenced at the path pointer.
But the issue is that you only have the path pointer, but you know little about how it has been allocated when it's been given to the function. How has it been allocated, and how much memory was allocated? What "useful" size is it (though that one can be guessed with strlen())?
Oh, and finally, don't forget to free() your allocations once you're done with them. Do not leak memory, that's rude! ☺
edit:
ok, here are stuff I can see that are wrong, and some comments about it:
char *removesubString(char *path, char **args){
char *dir;
int COUNT = 100;
char **dirs = malloc(sizeof(char*)*COUNT);
int i, position;
/* for both XXX marks below:
*
* below, sizeof(args) will return the size of the pointer
* not the number of items it contains. You *NEED* to pass
* a "int argc" as parameter to your function, that gives
* the numbers of items in the array.
* Think about why you have argc in the main() function construct:
* int main(int argc, const char** argv)
* _OR_ if the args array of strings is _ALWAYS_ terminated
* by a NULL item, then you should do: */
// int i = 0;
// while(args[i] != NULL) {
// /* do stuff */
// ++i;
// }
for (i = 2; i < sizeof(args) /* XXX */; i++) {
if(args[i] == NULL){ /* XXX */
break;
}
dir = strtok(path, PATH_DELIM);
position = 0;
while (dir != NULL) {
if(strcmp(dir, args[i]) == 0){
dir = strtok(NULL, PATH_DELIM);
continue;
}
/* because within the function you have no guarantee
* on the number of tokens within path, if you have
* more than 100 tokens, you will overflow the dirs array.
* a good idea would be to test whether position is bigger
* than or equal to COUNT, and if it is use realloc to
* extend dirs */
dirs[position] = dir;
position++;
dir = strtok(NULL, PATH_DELIM);
/* you could avoid having twice the former line
* and instead make your loop body being: */
// while (dir != NULL) {
// if(strcmp(dir, args[i]) != 0){
// /* TODO: check position vs COUNT and realloc dirs if necessary */
// dirs[position] = dir;
// ++position;
// }
// dir = strtok(NULL, PATH_DELIM);
// }
}
dirs[position] = NULL;
}
char *line;
line = ""; /* ← here you allocate line with a string of length 1 */
for (i = 0; i < position; i++) {
// so here, you'll write up to the number of characters
// within dirs[i], into a string of length one.
strncpy(line, dirs[i], strlen(dirs[i]));
}
/* And even if it was working you'd be assigning the line
* variable to a new value at each iteration, ending up doing
* something equivalent to the following line, but with "position"
* numbers of iterations: */
// strncpy(line, dirs[position-1], strlen(dirs[position-1]));
/* Don't forget to free the instances you've allocated dynamically
* before leaving the function: */
// free(dirs);
/* And finally there's another issue here, you're returning
* a variable that has been statically allocated above, so that
* when you'll try to use the pointed instance in the calling
* context, that variable won't exist anymore. */
return line;
}
HTH
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.