I am trying to print all possible combinations of the string 'abc' using C. Can someone help point out where in this code I am going wrong ? I am using the algorithm mentioned here:
http://hackercs.com/videos/Combinations-of-a-String-Part-2/
Thanks for your time and help. ( BTW, the goal is to use recursion here)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void combination(char **curString,int allowedStart,char **outBuffer,int length)
{
//check for allowed chars.
// if not return.
// else
// for each char in the allowed char
// copy into buffer
//print buffer
//combine buffer and over next allowed chars
//remove from buffer.
if (allowedStart == length)
return;
else
{
int curr;
for (curr = allowedStart;curr<length; curr++){
//need to copy 'a' into outbuffer and keep appending to outbuffer.
printf("allowedStart = %d\n",allowedStart);
printf("curr = %d\n",curr);
(*outBuffer)[curr] = (*curString)[allowedStart];
printf("outbuff is %s\n",*outBuffer);
combination(curString,curr+1,outBuffer,length);
printf("return\n");
(*outBuffer)[length-1] = '\0';
} //else
} //for
}
main()
{
char *var = "abc";
int length = strlen(var);
printf("length = %d\n",length);
char *outBuffer = malloc ( length * sizeof (char));
bzero(outBuffer,3);
combination(&var,0,&outBuffer,length);
}
For starters, you're going wrong here:
char *var = "abc";
int length = strlen(var);
printf("length = %d\n",length);
char *outBuffer = malloc ( length * sizeof (char));
bzero(outBuffer,3);
This is very confused code. It's mixing dynamic buffer length handling (the strlen() call) with static ones (the 3 in the bzero() call). It's also Doing It Wrong, by using sizeof (char) (which is guaranteed to be 1 by the C language, and thus just adds noise and confusion). Also, the number of characters needed to hold a 3-character printable string in C is not 3, but 4 since you need one character for the terminating '\0'.
Got this working.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void combination(char **curString,int allowedStart,char **outBuffer,int length)
{
//check for allowed chars.
// if not return.
// else
// for each char in the allowed char
// copy into buffer
//print buffer
//combine buffer and over next allowed chars
//remove from buffer.
int curr;
if ( allowedStart == length )
return;
else {
for (curr = allowedStart;curr<length; curr++){
//need to copy 'a' into outbuffer and keep appending to outbuffer.
// printf("allowedStart= %d curr= %d \n",allowedStart,curr);
(*outBuffer)[curr] = (*curString)[allowedStart];
//adjust for appending.
int i = 0;
while (i < length)
{
if ( ((*outBuffer)[i] == '\0') && ((*outBuffer)[i+1] != '\0') )
{
// printf("in here\n");
(*outBuffer)[i] = (*outBuffer)[i+1];
(*outBuffer)[i+1] = '\0';
}
i++;
}
// printf("added curr%d %c \n",curr, (*outBuffer)[curr]);
printf("***************************************COMBO: %s\n",*outBuffer);
allowedStart = curr+1;
// printf("allowedStart%d %c \n",allowedStart,(*curString)[allowedStart]);
combination(curString,allowedStart,outBuffer,length);
// printf("removing%d %c\n",curr,(*outBuffer)[curr]);
(*outBuffer)[curr] = ' ';
// printf("**************RETURNCOMBO: %s\n",*outBuffer);
} //else
} //for
}
main()
{
char *var = "abcd";
int length = strlen(var);
printf("length = %d\n",length);
// printf("Intial word is %s\n",var);
char *outBuffer = malloc ( (length+1) * sizeof (char));
bzero(outBuffer,length);
combination(&var,0,&outBuffer,length);
}
#include <iostream>
#define PRINTLN(STR) std::cout << STR << std::endl
#define SWAP(ARRAY, I, J) if(I != J) { ARRAY[I] ^= ARRAY[J]; ARRAY[J] ^= ARRAY[I]; ARRAY[I] ^= ARRAY[J]; }
void PrintCombinations_Rec(char* str, size_t idx)
{
const size_t len = strlen(str);
if( len == idx)
PRINTLN(str);
else
{
for (size_t i = idx; i < len; ++i)
{
SWAP(str, idx, i);
PrintCombinations_Rec(str, idx + 1);
SWAP(str, i, idx);
}
}
}
void PrintCombinations(const char* input)
{
const size_t len = strlen(input);
char* str = new char[len + 1];
strncpy_s(str, len + 1, input, len);
// Recursive call
PrintCombinations_Rec(str, 0);
delete[] str;
}
int main(int argc, char** argv)
{
PrintCombinations("ABCD");
return EXIT_SUCCESS;
}
Related
I am having trouble with the very last line in my function, where I am stilly learning the basics of C. I have the signature of this function given and am tasked to write a function to concatenate two strings. The commented line outputs the correct result.
#include <stdio.h>
#include <stdlib.h>
// 1) len = dst-len + max_dst_len
int strlcat(char *dst, const char *src, int max_dst_len) {
int len = 0;
while (dst[len] != '\0') {
len++;
}
int total_len = len + max_dst_len;
char *new_str = malloc(sizeof(char) * total_len);
for (int i = 0; i < len; i++) {
new_str[i] = dst[i];
}
for (int i = len; i < total_len; i++) {
new_str[i] = src[i - len];
}
new_str[total_len] = '\0';
//printf("%s <--\n", new_str);
dst = *new_str;
return total_len;
}
int main() {
char test1[] = "dst";
char test1src[] = "src";
printf("%s\n", test1);
printf("%d\n", strlcat(test1, test1src, 10));
printf("%s\n", test1);
}
You should not be adding max_dst_len to the length of dst. max_dst_len is the amount of memory that's already allocated in dst, you need to ensure that the concatenated string doesn't exceed this length.
So you need to subtract len from max_dst_len, and also subtract 1 to allow room for the null byte. This will tell you the maximum number of bytes you can copy from src to the end of dst.
In your main() code, you need to declare test1 to be at least 10 bytes if you pass 10 as the max_dst_len argument. When you omit the size in the array declaration, it sizes the array just big enough to hold the string you use to initialize it. It's best to use sizeof test1 as this argument, to ensure that it's correct for the string you're concatenating to.
#include <stdio.h>
int strlcat(char *dst, const char *src, int max_dst_len) {
int len = 0;
while (dst[len] != '\0') {
len++;
}
int len_to_copy = max_dst_len - len - 1;
int i;
for (i = 0; i < len_to_copy && src[i] != '\0'; i++) {
dst[len+i] = src[i];
}
dst[i] = '\0';
//printf("%s <--\n", new_str);
return i + len;
}
int main() {
char test1[6] = "dst";
char test1src[] = "src";
printf("%s\n", test1);
printf("%d\n", strlcat(test1, test1src, sizeof test1));
printf("%s\n", test1);
}
Hello guys so I am learning C and I am creating the strcat function and when I print out the values of dest at the index i concatenate a char at I get that char but when I return dest and print it out back in my main function the changes aren't reflected. Can someone please help me out? thanks.
#include <stdio.h>
#include <stdlib.h>
int size_s(char *str) {
int size = 0;
int index = 0;
while (str[index] != '\0') {
size += 1;
index += 1;
}
return (size + 1);
}
/*
* #function: strcat
* #desc: Takes in two char pointers and concatenates them. provided the destination has enough size otherwise undefined behavior can occur. Overwrites the null terminator
*/
char *strcat_s(char *dest, char *source)
{
int index_of_src = 0;
int index_of_dest = size_s(dest);
while (source[index_of_src] != '\0') {
*(dest + index_of_dest) = source[index_of_src];
index_of_src += 1;
index_of_dest += 1;
}
// Add Null terminator
*(dest + (index_of_dest + 1)) = '\0';
return dest;
}
int main(int argc, char **argv) {
char firstname[100];
scanf("%s", firstname);
char lastname[100];
scanf("%s", lastname);
int sizeofFirst = size_s(firstname);
printf("Sizeof first: %d\n", sizeofFirst);
int sizeofSecond = size_s(lastname);
printf("Sizeof second: %d\n", sizeofSecond);
char *concatinated = strcat_s(firstname, lastname);
printf("%s\n", concatinated);
}
The function size_s returns the index of the character after the zero-terminating character '\0' due to this return statement
return (size + 1);
So in this while loop
int index_of_src = 0;
int index_of_dest = size_s(dest);
while(source[index_of_src] != '\0')
{
*(dest + index_of_dest) = source[index_of_src];
index_of_src += 1;
index_of_dest += 1;
}
the array pointed to by the pointer dest is filled after the terminating zero character '\0'.
As a result this call of printf
printf("%s\n", concatinated);
outputs the initially stored string in the array firstname.
Rewrite the function size_s the following way
size_t size_s( const char *s )
{
size_t n = 0;
while ( s[n] != '\0' ) ++n;
return n;
}
In turn the function strcat_s that should be renamed because there is standard function strcat_s can look for example the following way
char * strcat_str( char *dest, const char *source )
{
size_t n = size_s( dest );
while ( ( *( dest + n++ ) = *source++ ) != '\0' );
return dest;
}
There are multiple issues in your code:
the size_s function really computes the size of the string, including the null terminator, but counting the null terminator is not helping for the task at hand, you should instead compute the length of the string, ie: the number of bytes before the null terminator, which is exactly the offset where to copy the second string at the end of the first.
*(dest + (index_of_dest + 1)) = '\0'; does not store the null terminator at the correct place: it places it one step too far. You should write *(dest + index_of_dest) = '\0'; or simply dest[ndex_of_dest] = '\0';
the name strcat_s may conflict with a library function of the same name defined in the infamous Annex K of the C Standard. A different name is preferable.
scanf("%s", firstname); is a security flaw: sufficient long input will cause a buffer overflow and carefully crafted input may allow the user to execute arbitrary code. Use scanf("%99s", firstname); to avoid this.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
int my_strlen(const char *str) {
int index = 0;
while (str[index] != '\0') {
index += 1;
}
return index;
}
/*
* #function: strcat
* #desc: Takes in two char pointers and concatenates them. provided the destination has enough size otherwise undefined behavior can occur. Overwrites the null terminator
*/
char *my_strcat(char *dest, const char *source) {
int index_of_src = 0;
int index_of_dest = my_strlen(dest);
while (source[index_of_src] != '\0') {
dest[index_of_dest] = source[index_of_src];
index_of_src += 1;
index_of_dest += 1;
}
// Add the null terminator
dest[index_of_dest] = '\0';
return dest;
}
int main(int argc, char **argv) {
char firstname[200];
char lastname[100];
if (scanf("%99s %99s", firstname, lastname) != 2)
return 1;
printf("length of first: %d\n", my_strlen(firstname));
printf("length of second: %d\n", my_strlen(lastname));
char *concatenated = my_strcat(firstname, lastname);
printf("%s\n", concatenated);
printf("length of concatenation: %d\n", my_strlen(concatenated));
return 0;
}
I'm trying to solve a challenge, but I have no idea of what's wrong with my code!
The challenge is:
Create a function that splits a string of characters into words.
Separators are spaces, tabs and line breaks.
This function returns an array where each box contains a character-string’s address represented by a word. The last element of this array should be equal to 0 to emphasise the end of the array.
There can’t be any empty strings in your array. Draw the necessary conclusions.
The given string can’t be modified.
Note: The only allowed function is malloc()
The bug/problem:
I faced this problem and I tried to solve it but I wasn't able to identify what's wrong.
I created a function named split_whitespaces() to do the job.
When I print the array of strings inside of the split_whitespaces function, I get the following output:
Inside the function:
arr_str[0] = This
arr_str[1] = is
arr_str[2] = just
arr_str[3] = a
arr_str[4] = test!
And when I print the array of string inside the main function, I get the following output:
Inside the main function:
arr_str[0] = #X#?~
arr_str[1] = `X#?~
arr_str[2] = just
arr_str[3] = a
arr_str[4] = test!
I created a function word_count to count how many words in the input string so I can allocate memory using malloc and with word_count + 1 (null pointer).
int word_count(char *str) {
int i;
int w_count;
int state;
i = 0;
w_count = 0;
state = 0;
while (str[i]) {
if (!iswhitespace(str[i])) {
if (!state)
w_count++;
state = 1;
i++;
} else {
state = 0;
i++;
}
}
return (w_count);
}
And another function called strdup_w to mimic the behavior of strdup but just for single words:
char *strdup_w(char *str, int *index) {
char *word;
int len;
int i;
i = *index;
len = 0;
while (str[i] && !iswhitespace(str[i]))
len++, i++;;
word = (char *) malloc(len + 1);
if (!word)
return (NULL);
i = 0;
while (str[*index]) {
if (!iswhitespace(str[*index])) {
word[i++] = str[*index];
(*index)++;
} else
break;
}
word[len] = '\0';
return (word);
}
Here's my full code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **split_whitespaces(char *str);
char *strdup_w(char *str, int *index);
int word_count(char *str);
int iswhitespace(char c);
int main(void) {
char *str = "This is just a test!";
char **arr_str;
int i;
i = 0;
arr_str = split_whitespaces(str);
printf("\nOutside the function:\n");
while (arr_str[i]) {
printf("arr_str[%d] = %s\n", i, arr_str[i]);
i++;
}
return (0);
}
char **split_whitespaces(char *str) {
char **arr_str;
int i;
int words;
int w_i;
i = 0;
w_i = 0;
words = word_count(str);
arr_str = (char **)malloc(words + 1);
if (!arr_str)
return (NULL);
printf("Inside the function:\n");
while (w_i < words) {
while (iswhitespace(str[i]) && str[i])
if (!str[i++])
break;
arr_str[w_i] = strdup_w(str, &i);
printf("arr_str[%d] = %s\n", w_i, arr_str[w_i]);
w_i++;
}
arr_str[words] = 0;
return (arr_str);
}
char *strdup_w(char *str, int *index) {
char *word;
int len;
int i;
i = *index;
len = 0;
while (str[i] && !iswhitespace(str[i]))
len++, i++;;
word = (char *)malloc(len + 1);
if (!word)
return (NULL);
i = 0;
while (str[*index]) {
if (!iswhitespace(str[*index])) {
word[i++] = str[*index];
(*index)++;
} else
break;
}
word[len] = '\0';
return (word);
}
int word_count(char *str) {
int i;
int w_count;
int state;
i = 0;
w_count = 0;
state = 0;
while (str[i]) {
if (!iswhitespace(str[i])) {
if (!state)
w_count++;
state = 1;
i++;
} else {
state = 0;
i++;
}
}
return (w_count);
}
int iswhitespace(char c) {
if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
return (1);
return (0);
}
I'm sorry, if anything this is my first time trying to seek help.
There are multiple problems in the code:
the size is incorrect in arr_str = (char **)malloc(words + 1); You must multiply the number of elements by the size of the element:
arr_str = malloc(sizeof(*arr_str) * (words + 1));
it is good style to free the array in the main() function after use.
the test while (iswhitespace(str[i]) && str[i]) is redundant: if w_count is computed correctly, testing str[i] should not be necessary. You should use strspn() to skip the white space and strcspn() to skip the word characters.
if (!str[i++]) break; is completely redundant inside the loop: str[i] has already been tested and is not null.
while (str[i] && !iswhitespace(str[i])) len++, i++;; is bad style. Use braces if there is more than a single simple statement in the loop body.
the last loop in strdup_w is complicated, you could simply use memcpy(word, str + *index, len); *index += len;
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
char **split_whitespaces(const char *str);
char *strdup_w(const char *str, int *index);
int word_count(const char *str);
int iswhitespace(char c);
int main(void) {
const char *str = "This is just a test!";
char **arr_str;
int i;
arr_str = split_whitespaces(str);
if (arr_str) {
printf("\nOutside the function:\n");
i = 0;
while (arr_str[i]) {
printf("arr_str[%d] = %s\n", i, arr_str[i]);
i++;
}
while (i --> 0) {
free(arr_str[i]);
}
free(arr_str);
}
return 0;
}
char **split_whitespaces(const char *str) {
char **arr_str;
int i;
int words;
int w_i;
i = 0;
w_i = 0;
words = word_count(str);
arr_str = malloc(sizeof(*arr_str) * (words + 1));
if (!arr_str)
return NULL;
printf("Inside the function:\n");
while (w_i < words) {
while (iswhitespace(str[i]))
i++;
arr_str[w_i] = strdup_w(str, &i);
if (!arr_str[w_i])
break;
printf("arr_str[%d] = %s\n", w_i, arr_str[w_i]);
w_i++;
}
arr_str[words] = NULL;
return arr_str;
}
char *strdup_w(const char *str, int *index) {
char *word;
int len;
int start;
int i;
i = *index;
start = i;
while (str[i] && !iswhitespace(str[i])) {
i++;
}
*index = i;
len = i - start;
word = malloc(len + 1);
if (!word)
return NULL;
i = 0;
while (i < len) {
word[i] = str[start + i];
i++;
}
word[i] = '\0';
return word;
}
int word_count(const char *str) {
int i;
int w_count;
int state;
i = 0;
w_count = 0;
state = 0;
while (str[i]) {
if (!iswhitespace(str[i])) {
if (!state)
w_count++;
state = 1;
} else {
state = 0;
}
i++;
}
return w_count;
}
int iswhitespace(char c) {
return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
}
From my top comment ...
In split_whitespaces, try changing:
arr_str = (char **) malloc(words + 1);
into:
arr_str = malloc(sizeof(*arr_str) * (words + 1));
As you have it, words is a count and not a byte length, so you're not allocating enough space, so you have UB.
UPDATE:
But watched some tutorials and they said that malloc takes one argument which is the size of the memory to be allocated (in bytes), that's why I allocated memory for 5 bytes! can you please tell my an alternative of using malloc without sizeof() function. I'll appreciate it. – Achraf EL Khnissi
There's really no clean way to specify this without sizeof.
sizeof is not a function [despite the syntax]. It is a compiler directive. It "returns" the number of bytes occupied by its argument as a compile time constant.
If we have char buf[5];, there are 5 bytes, so sizeof(buf) [or sizeof buf] is 5.
If we have: int buf[5];, there are 5 elements, each of size int which is [typically] 4 bytes, so the total space, in bytes, is sizeof(int) * 5 or 4 * 5 which is 20.
But, int can vary depending on the architecture. On Intel 8086's [circa the 1980's], an int was 2 bytes (i.e. 16 bits). So, the above 4 * 5 would be wrong. It should be 2 * 5.
If we use sizeof(int), then sizeof(int) * 5 works regardless of the architecture.
Similarly, on 32 bit machines, a pointer is [usually] 32 bits. So, sizeof(char *) is 4 [bytes]. On a 64 bit machine, a pointer is 64 bits, which is 8 bytes. So, sizeof(char *) is 8.
Because arr_str is: char **arr_str, we could have done:
arr_str = malloc(sizeof(char *) * (words + 1));
But, if the definition of arr_str ever changed (to (e.g.) struct string *arr_str;), then what we just did would break/fail if we forgot to change the assignment to:
arr_str = malloc(sizeof(struct string) * (words + 1));
So, doing:
arr_str = malloc(sizeof(*arr_str) * (words + 1));
is a preferred idiomatic way to write cleaner code. More statements will adjust automatically without having to find all affected lines of code manually.
UPDATE #2:
You might just add why you removed the (char **) cast :) -- chqrlie
Note that I removed the (char **) cast. See: Do I cast the result of malloc?
This just adds extra/unnecessary "stuff" as the void * return value of malloc can be assigned to any type of pointer.
If we forgot to do: #include <stdlib.h>, there would be no function prototype for malloc, so the compiler would default the return type to int.
Without the cast, the compiler would issue an an error on the statement [which is what we want].
With the cast, this action is masked at compile time [more or less]. On a 64 bit machine, the compiler will use a value that is truncated to 32 bits [because it thinks malloc returns a 32 bit value] instead of the full 64 bit return value of malloc.
This truncation is a "silent killer". What should have been flagged as a compile time error produces a runtime fault (probably segfault or other UB) that is much harder to debug.
This is my program:
Does anyone know why it doesn't work?
My professor asked me to remove a character at an index using pointers, I'm also not allowed to use a for - loop so I'm kind of lost.
int count = 0;
int strl = strlen(s);
char s2 [strl-1];
if (index >= 0 && index < strl){
while(count < strl){
if (count == index){
*(s+index) == *s;
strl--;
}
count++;
}
printString(s);
}
}
Your program won't work because your program don't modify strings.
You can use memmove() to shift the string after the character to be removed left by one character to remove a character. (Pointers are used as the arguments of memmove())
#include <stdio.h>
#include <string.h>
void removeAt(char* str, int idx) {
size_t len = strlen(str);
memmove(str + idx, str + idx + 1, len - idx);
}
int main(void) {
char target[] = "0123456789";
printf("before removing : %s\n", target);
removeAt(target, 5);
printf("after removing : %s\n", target);
return 0;
}
Output:
before removing : 0123456789
after removing : 012346789
In order to remove a character at index i from a string you need to move every character after it one space back:
void remove_at(char* s, size_t i) {
if (!s) return;
while (s[i]) {
s[i] = s[i+1];
i++;
}
}
It's undefined behavior to pass an i >= strlen(s), so beware.
Here is an example using pointers to delete a character at a specific index in a string:
#include <assert.h>
#include <stdio.h>
#include <string.h>
void DeleteChar(int index, char string[])
{
char *ptr;
assert(index >= 0);
assert(index < strlen(string));
ptr = string + index;
while (*ptr != '\0') {
*ptr = *(ptr + 1);
ptr++;
}
}
int main(void)
{
char string[] = "hello world";
DeleteChar(9, string);
puts(string);
return 0;
}
Note, however, that it is safer and simpler to use only indices instead of pointers.
The code below reads characters and splits them into C-style strings when a delimiter is encountered, then it stores the words (white-space-separated sequences of characters) in string array till a sentinel is encountered; updates size of string array:
#include <stdio.h> // printf()
#include <stdlib.h> // malloc(); realloc()
#include <string.h> // strcmp()
#include <stddef.h> // size_t
void print_array(char* arr[ ], size_t size); // forward declaration to use in to_array()
char* get_word(char delimiter)
{
size_t size = 8;
size_t index = 0;
int c = 0;
char* word = 0;
char* expand_word = 0;
word = (char*) malloc(sizeof(char) * size);
if (word == NULL)
{
perror("get_word::bad malloc!\n");
exit(-1);
}
while ((c = getchar()) != EOF && c != delimiter && c != '\n')
{
if (index >= size)
{
size *= 2;
expand_word = (char*) realloc(word, sizeof(char) * size);
if (expand_word == NULL)
{
perror("get_word::bad realloc!\n");
exit(-1);
}
word = expand_word;
}
word[index++] = c;
}
word[index] = 0;
return word;
}
//-------------------------------------------------------------------------------------
void to_array(char* arr[ ], size_t* size, char* sentinel)
{
size_t index = 0;
char* word = 0;
char** expand_arr = 0;
char delimiter = ' ';
while ((word = get_word(delimiter)) && strcmp(word, sentinel) != 0)
{
if (index >= (*size))
{
(*size) *= 2;
expand_arr = (char**) realloc(arr, sizeof(char*) * (*size));
if (expand_arr == NULL)
{
perror("to_array::bad realloc!\n");
exit(-1);
}
arr = expand_arr;
}
arr[index++] = word;
}
(*size) = index;
// print_array(arr, *size); // <---- here, all words printed OK.
// getchar();
}
//-------------------------------------------------------------------------------------
void print_array(char* arr[ ], size_t size)
{
size_t i = 0;
printf("{ ");
for (i; i < size; ++i)
{
printf("%s", arr[i]);
if (i < size - 1)
{
printf(", ");
}
}
printf(" }\n");
}
//-------------------------------------------------------------------------------------
int main()
{
size_t size = 4;
char** arr = 0;
char* sentinel = "quit";
arr = (char**) malloc(sizeof(char*) * size);
if (arr == NULL)
{
perror("array of strings::bad malloc!\n");
exit(-1);
}
printf("Type a sentence and get each word as an array element:\n");
to_array(arr, &size, sentinel);
printf("Words:\n");
print_array(arr, size); // <--------- here, error!
getchar();
}
When trying to print the string array, I get:
Access violation reading location 0xcd007361.
Why I can't print the strings in arr at the end?
P.S.: I guess that the problem comes from the pointer arithmetic and the reallocation of the char** arr within function to_array(). (If previous right) I'm not sure what would be the standard way to deal with it?
Problem: the first parameter in void to_array(), i.e. char* arr[ ] passes a copy of a pointer to array of char. Every change on the pointer made inside the function does not affect the actual pointer to char array outside, specifically the function realloc() may move the initial memory block to a new location, which would invalidate the pointer passed as first parameter.
Solution: either to modify the function void to_array() to return the modified arr, or to modify the first parameter of the function to char** arr[ ]. The latter was chosen and the modified code looks like this:
void to_array(char** arr[ ], size_t* size, char* quit)
{
size_t index = 0;
char* word = 0;
char** expand_arr = 0;
char sentinel = ' ';
while ((word = get_word(sentinel)) && strcmp(word, quit) != 0)
{
if (index >= (*size))
{
(*size) *= 2;
expand_arr = (char**) realloc((*arr), sizeof(char*) * (*size));
if (expand_arr == NULL)
{
perror("to_array::bad realloc!\n");
exit(-1);
}
(*arr) = expand_arr;
}
(*arr)[index++] = word;
}
(*size) = index;
}
then the function call must be done as:
to_array(&arr, &size, quit);