but the methods here does not seems to be working for me.
In that code the "string array" is declared as
char sub_str[10][20]; // [1]
You declared the function maybe as
char** toStrArray(char str[], char **strArr): // [2]
And these are different animals
In general you do not mix [] and ** notation. You can declare just
char** toStrArray(char* str, char** strArr); // [3]
The returned value would be the same as strArr. The reason for that is the convenience of being able to use the function call in an expression. See fgets() for example.
But
and it will be an array of strings only if each of the 10 20-byte segments are null-terminated. At first it is just a block of char
[2] is a pointer to a pointer to char
char** strArray;
*strArray is a pointer to char
**strArray is a char
and it will never be an array of char. But it can be an array of pointers to char and it would be the most flexible use since we could then iterate over the pointers pointed by **strArray, writing code like *strArray[0], *srtArray[1] and so on. An array of strings
in both cases the "arrays" must be constructed carefully or you will get no array, no strings, leak memory or crash your program
I will show an example of each case
The first case maybe somewhat off-topic but I think it makes sense in order to compare things often confused
building sub_str[10][20]
Here we have just an area of 10*20*sizeof(char) bytes. There is no such thing as multidimensional arrays in C. Each 20-byte segment are just laid down one after another starting at &sub_str.
Since each string is null terminated we can have up to 10 strings up to 19 bytes each in size. Here is a C program that fills such a block
#include <stdio.h>
int main(void)
{
char sub_str[10][20];
for (int i = 0; i < 10; i += 1)
sprintf(
sub_str[i],
"%16s%03d",
"This is string ", i+1
);
for (int i = 0; i < 10; i += 1)
printf(
"%2d %s len(%zd)\n",
i, sub_str[i], strlen(sub_str[i])
);
return 0;
};
This is the output
0 This is string 001 len(19)
1 This is string 002 len(19)
2 This is string 003 len(19)
3 This is string 004 len(19)
4 This is string 005 len(19)
5 This is string 006 len(19)
6 This is string 007 len(19)
7 This is string 008 len(19)
8 This is string 009 len(19)
9 This is string 010 len(19)
And we have an array of strings. See the printf() iterating accessing the i-th one below
printf(
"%2d %s len(%zd)\n",
i, sub_str[i], strlen(sub_str[i])
);
Problem here is that we have little flexibility and possibly a lot of wasted memory. All sizes are fixed, static
Building char** strArray; finally
This is the most flexible and familiar way, since every C program uses at least one case. main() has the common prototype
int main(int argc, char** argv);
And here we see an all-important thing missing in your program: since srtArray is just a pointer, you need to know to how many pointers it points to.
By itself *strArray is just a pointer to char. And only if it is allocated. By declaring char** strArr; you get just a pointer, and in fact it would the safe to write
char** strArr = NULL;
Consider this
typedef struct
{
int argc;
char** argv;
} stringArray;
And now the ends meet. In fact you could have declared
void toStrArray(char* str, stringArray strArr);
and pack the argc value into the struct after all
About the program: the code just mimics what the system does for main(), building a list of strings from the command line parameters, even including the program name as the fist one. And then calls this function
int just_like_main(int argc, char** argv)
that prints out the arguments.
It does what you must do in your function.
Note that you must have a way to control the number of strings in your array, at all times, just like argc in main(). It is essential to have this in mind.
Here is the code
#define _BLOCK_ 4
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
int argc;
char** argv;
} stringArray;
int just_like_main(int, char**);
int main(void)
{
const int n_parm = 16;
const char* test_strings[16] =
{
"Creating", "a", "block", "of",
"strings", ",", "just", "like",
"the", "system", "does", "for" ,
"main()", "for", "every", "program"
};
stringArray ex; // example
int N = _BLOCK_; // 1st block
ex.argc = 0;
ex.argv = (char**)malloc(sizeof(char*) * _BLOCK_);
const char* program_name = "full path of program";
ex.argv[ex.argc] = (char*)malloc(1 + strlen(program_name));
strcpy(ex.argv[ex.argc], program_name);
ex.argc += 1; // 1st arg. That was easy
// loads all other strings into **argv
for (int i = 0; i < n_parm; i += 1)
{ // each one
if (ex.argc >= N)
{ // block is full
N = N + _BLOCK_;
char* new_block = realloc(ex.argv, (N * sizeof(char*)));
printf("Block extended for a total of %d pointers\n", N);
ex.argv = (char**)new_block;
};
ex.argv[ex.argc] = (char*)malloc(1 + strlen(test_strings[i]));
strcpy(ex.argv[ex.argc], test_strings[i]);
ex.argc += 1;
}; // for()
printf("\t%d strings in the block:\n", ex.argc);
for (int i = 0; i < ex.argc; i += 1)
{
printf("\t\t%d of %d: '%s'\n", 1 + i, ex.argc, ex.argv[i]);
};
// now trims the end of the block
// allocated: N.
// used: argc
printf("\t%d pointers allocated\n", N);
printf("\t%d arguments read\n", ex.argc);
if (N == ex.argc)
printf("\tNothing to free()\n");
else
{
printf("\t%d pointers to free\n", N - ex.argc);
char* new_size = realloc(ex.argv, (ex.argc * sizeof(char*)));
printf("\tBlock size trimmed for a total of %d pointers\n", ex.argc);
ex.argv = (char**)new_size;
};
printf("\tCalling just_like_main() with these args\n");
int res = just_like_main(ex.argc, ex.argv);
printf("\n\n\t\"main()\" returned %d\n", res);
printf("\tNow fres the block and exit\n");
for (int i = 0; i < ex.argc; i += 1)
free(ex.argv[i]);
free(ex.argv);
printf("\n\nGame over\n");
return 0;
};
int just_like_main(int argc, char** argv)
{
printf("\n\tAt \"main()\": %d arguments\n\n", argc);
for (int i = 0; i < argc; i += 1)
printf("%8d\t'%s'\n", i, argv[i]);
return 0;
}; // just_like_main()
And the output
Block extended for a total of 8 pointers
Block extended for a total of 12 pointers
Block extended for a total of 16 pointers
Block extended for a total of 20 pointers
17 strings in the block:
1 of 17: 'full path of program'
2 of 17: 'Creating'
3 of 17: 'a'
4 of 17: 'block'
5 of 17: 'of'
6 of 17: 'strings'
7 of 17: ','
8 of 17: 'just'
9 of 17: 'like'
10 of 17: 'the'
11 of 17: 'system'
12 of 17: 'does'
13 of 17: 'for'
14 of 17: 'main()'
15 of 17: 'for'
16 of 17: 'every'
17 of 17: 'program'
20 pointers allocated
17 arguments read
3 pointers to free
Block size trimmed for a total of 17 pointers
Calling just_like_main() with these args
At "main()": 17 arguments
0 'full path of program'
1 'Creating'
2 'a'
3 'block'
4 'of'
5 'strings'
6 ','
7 'just'
8 'like'
9 'the'
10 'system'
11 'does'
12 'for'
13 'main()'
14 'for'
15 'every'
16 'program'
"main()" returned 0
Now free() the block and exit
Game over
About the logic
Memory will be allocated in blocks of size _BLOCK_ pointers. Anytime memory runs out a new block of the same size is allocated. At exit the complete block is trimmed to the used size and the rest is 'free()'
Ex: for 12 strings and _BLOCK_ of 5 3 blocks will be allocated for a total of 15. At the end the last 3 pointers are freed so the function returns a block of just 12 pointers, as expected.
In practical applications we must choose this value carefully in order to not allocate very much AND not allocate very often :)
Just for fun the first parameter will be the name of the program and a function declared
int just_like_main(int argc, char** argv);
will be called and it just displays the full parameter block
*(strArr + j) = tmp;you always set the same (temporary) string instrArrand "erase" its contentmemset()ing everything to 0 few lines after. also please remember that strings in c should be terminated by\0and check for memory leaks/problems with a tool likevalgrind.strArr + jpoints to the sametmp./* Assign the copied words to strArr */is a misleading comment. This line doesn't do that. It assigns a pointer — always the same pointer,tmp.