How to find the number of elements in char** array? - c

I have an string array in the form of char**
I am struggling to find the length of that array:
typedef struct _stringArray
{
int (*Length)(char**);
char** (*Push)(char**, char*);
char** (*Pop)(char**, char*);
}StringArray;
StringArray* StringArray_Constructor(void)
{
StringArray* stringArray = (StringArray *)malloc(sizeof(StringArray));
stringArray->Push = StringArray_Push;
stringArray->Pop = StringArray_Pop;
}
char** StringArray_Push(char** array, char* string)
{
int size = 0; //how to find how many elements in the array object???
array = realoc(array, (sizeof(char *) * (size + 1));
array[size] = string;
return array;
}
Any help would be greatly appreciated!
Thanks.

With C, you will have to keep track of this yourself.

There's no way you can infere the lenght of the array, the only way you could do it is doing it dynamically. You have an array of strings (char**), so you have the pointer to the first character of the first element of the array. We all know that, in C, all strings must ed with '\0', so you can "scan" for the strings of the array taking this pointer and saving it, then increment it until you get a '\0'. The next pointer is the first character of the next string and so on.
But this have a huge flaw: memory is not as linear as it appears. What I'm saying is that your first string can be entirely allocated at, e.g., address 0x0010101A, and the next at 0xF0FF0001, so or you hae a huge string #0x0010101A or there is a bunch of data beetween them and you do not know if they are part of the string or not.
And that's why you need to maintain a counter of how many strings you have. :)
PS: and as this number is always greater than zero, you should use unsigned int to type it.

You have a few options:
1) Pass a size parameter around which indicates the current size of your char **array.
2) Declare a structure which combines char **array with int array_size (really the same as #1).
3) If your array will always contain valid pointers (i.e. non-NULL) then create an extra element at the end which is always set to NULL. This acts as an array terminator, you can scan char **array looking for this terminating element:
int size;
for (size = 0; array[size] != NULL; size++);
// 'size' is number of valid entries in 'array'.

Related

Best way to initialize an array of strings to pass it to a function

I need to intialize an empty array of strings with fixed size ( 3 by 100 for example), pass it to a function to fill it with data and perform things like strcpy(), strcmp(), memset() on it. After the function is terminated I need to be able to read the data from my main().
What I tried so far:
char arrayofstrings[3][100] = {0};
char (*pointer)[3][100] = &arrayofstrings;
function(pointer);
Initalizing an (empty?) array of strings and initializing a pointer on the first element.
int function (char (*pointer)[3][100])
{
strcpy((*pointer)[i], somepointertostring);
strcmp((*pointer)[i], somepointertostring)
memset((*pointer)[i], 0, strlen((*pointer)[i]));
}
Is this a good way to do it? Is there an easier way to do it? Whats up with the brackets around the pointer?
C string functions expect a buffer to be null-terminated. Your arrayofstrings allocation happens on the stack. Depending on your compiler it might be initialized to all zeros or might contain garbage.
The simplest way in your case to make sure string functions won't overrun your buffers is to set the first character of each to 0 (null)
arrayofstrings[0][0] = 0x00;
arrayofstrings[1][0] = 0x00;
arrayofstrings[2][0] = 0x00;
This will give you 3, 100-char buffers that contain a valid empty "string". Note that you can only store 99 "characters" because the last character must be 0x00 (null-terminator).
char (*pointer)[3][100] = &arrayofstrings;
This is unnecessary.
Something to keep in mind about arrays in C is that the [] index is really only there to make things easier for the human programmer. Any array definition is simply a pointer to memory. The values inside the [][]...[] indexes and the type are used by the compiler to allocate the right amount of memory on the stack and do some simple math to come up with the right memory address for the element you want to access.
char arrayofstrings[3][100];
This will allocate sizeof(char)*3*100 bytes on the stack and give you a char* called 'arrayofstrings'. There's nothing special about the char* itself. It would be the same pointer if you had char arrayofstrings[300] or char arrayofstrings[3][10][10] or even long arrayofstrings[75] (char is 1 byte, long is 4 bytes).
Because you declared it as a multidimensional array with [a][b], when you ask for arrayofstrings[x][y], the compiler will calculate ((x*b)+y)*sizeof(type) and add it to the arrayofstrings pointer to get the address of the value you want. But because it's just a pointer, you can treat it like any other pointer and pass it around or cast it to other types of pointer or do pointer math with it.
You don't need the extra level of indirection.
An array, when passed to a function, is converted to a pointer to its first member. So if you declare the function like this:
int function(char (*pointer)[100])
Or equivalently:
int function(char pointer[][100])
Or:
int function(char pointer[3][100])
You can pass the array directly to the function:
function(arrayofstrings);
Then the body could look something like this:
strcpy(pointer[0], "some string");
strcpy(pointer[1], "some other string");
strcpy(pointer[2], "yet another string");
Best way to initialize an array of strings ...
char arrayofstrings[3][100] = {0}; is fine to initialize an array of strings.
In C, initialization is done only at object definition, like above.
Later code like strcpy(), assigns data to the array.
Best way to ... pass it to a function
When the C compiler supports variable length arrays, use function(size_t n, size_t sz, char a[n][sz]).
Add error checks.
Use size_t for array sizing and indexing.
#define somepointertostring "Hello World"
int function(size_t n, size_t sz, char arrayofstrings[n][sz]) {
if (sz <= strlen(somepointertostring)) {
return 1;
}
for (size_t i = 0; i < n; i++) {
strcpy(arrayofstrings[i], somepointertostring);
if (strcmp(arrayofstrings[i], somepointertostring)) {
return 1;
}
// Drop this it see something interesting in `foo()`
memset(arrayofstrings[i], 0, strlen(arrayofstrings[i]));
}
return 0;
}
void foo(void) {
char arrayofstrings[3][100] = {0};
size_t n = sizeof arrayofstrings / sizeof arrayofstrings[0];
size_t sz = sizeof arrayofstrings[0];
if (function(n, sz, arrayofstrings)) {
puts("Fail");
} else {
puts("Success");
puts(arrayofstrings[0]);
}
}
Initalizing an (empty?) array of strings and initializing a pointer on the first element.
The type of &arrayofstrings is char (*)[3][100] i.e. pointer to an object which is a 2D array of char type with dimension 3 x 100. So, this initialisation
char (*pointer)[3][100] = &arrayofstrings;
is not initialisation of pointer with first element of arrayofstrings array but pointer will point to whole 2D array arrayofstrings. That why, when accessing the elements using pointer you need bracket around it -
`(*pointer)[0]` -> first string
`(*pointer)[1]` -> second string and so on..
Is this a good way to do it? Is there an easier way to do it?
If you want pointer to first element of array arrayofstrings then you can do
char (*p)[100] = &arrayofstrings[0];
Or
char (*p)[100] = arrayofstrings;
both &arrayofstrings[0] and arrayofstrings are equivalent1).
Pass it to a function and access the array:
function() function signature should be -
int function (char (*pointer)[100])
// if you want the function should be aware of number of rows, add a parameter for it -
// int function (char (*pointer)[100], int rows)
this is equivalent to
int function (char pointer[][100])
and call it in from main() function like this -
function (p);
In the function() function you can access array as p[0], p[1] ...:
Sample program for demonstration:
#include <stdio.h>
#include <string.h>
#define ROW 3
#define COL 100
void function (char (*p)[COL]) {
strcpy (p[0], "string one");
strcpy (p[1], "string two");
strcpy (p[2], "string three");
}
int main(void) {
char arrayofstrings[ROW][COL] = {0};
char (*pointer)[COL] = &arrayofstrings[0];
function (pointer);
for (size_t i = 0; i < ROW; ++i) {
printf ("%s\n", arrayofstrings[i]);
}
return 0;
}
When you access an array, it is converted to a pointer to first element (there are few exceptions to this rule).

How to create variable size array that contains strings?

I have a problem trying to create a variable size array that contains strings. I have tried to create a multidimensional array, but it's too difficult. Example:
char *audio_types[8][40]; // 8 is number of string elements in the array by default; 40 is the maximum length of a string
audio_types = (char *) malloc(15); // increasing number of strings in the array
free(audio_types);
Moreover, I was trying to create variable size pointer array. Example:
char *audio_types[40]; // 40 is the maximum length of a string
*audio_types = (char *) malloc(8); // setting number of strings to 8
free(audio_types);
The problem is that I don't know how to create an array with variable number of string elements properly. Sorry, I am new in C programming. In the short, my code has to hold multiple string elements in one array. Example:
audio_types[0] // some string...
audio_types[1] // another string...
audio_types[2] // more another sting... etc.
Hope you understand what I am trying to ask. Thank you for your attention.
Maybe something like this. It will grow the size of the array when you add new types. It will also keep track of how many types you have in the array (it is needed if you resize the array dynamically and you need to know how many elements are in this array).
#define AUDIO_TYPE_LENGTH 40
typedef char audio_type[AUDIO_TYPE_LENGTH];
typedef struct
{
size_t size;
audio_type audio_types[];
}audioTypes_t;
audioTypes_t *AddType(audioTypes_t *types, const char *type)
{
size_t size = types ? types -> size : 0;
types = realloc(types, sizeof(*types) + (size + 1) * sizeof(types -> audio_types[0]));
if(types)
{
strncpy(types -> audio_types[size], type, sizeof(types -> audio_types[0] - 1));
types -> audio_types[size][sizeof(types -> audio_types[0] - 1)] = 0; //making strncpy safe
types -> size = size + 1;
}
return types;
}
You cannot change the size of an array in C. You could create a new array each time you want to resize and transfer the contents from the old array to the new one. Alternatively, you could use a list to store your strings.
When you define the array ( the char *audio_types[40]; line) in C it creates a contiguous block of memory to the 40 char pointers in the array. As memory is allocated when the array is defined you cannot make the array longer. To do that you would need a List data type, or you could create a new array when you want to add a new element which is the old one with the new element at the end.
char string[40] is an array of 40 characters that can hold 39 characters maximum (plus the string terminator) - the maximum size cannot be changed and 40 bytes of memory are used even if you store a short string containing 2 characters (plus the string terminator).
char *string is a pointer to some characters - the pointer can point anywhere: to a single character or any size array of characters. If it points to an array of characters (which you can make using malloc() then it can be thought of as a "string")
char *array[8] is an array of 8 "strings" (really it is 8 pointers to characters) The size of the array cannot be changed but the pointers can point anywhere: to a single character or any size array of characters. If the pointers point to an array of characters (which you can make using malloc() then they can be thought of as "strings")
char array[8][40] is a 2D array which you can think of as an array of 8 "strings" - where "strings" is defined as an array of 40 characters that can hold 39 characters maximum (plus the string terminator). You cannot change the size of either dimension.
char **array is a pointer to a char * - which could just be a single "string" or to an array of "strings". The sizes aren't fixed and can be dynamically created.
char *string1 = "asd"; means that string1 points to an array of 4 characters ("asd" plus the string terminator) that are in read-only memory - you cannot change the contents of the string but you can point string1 anywhere you want.
char string1[] = "asd"; means that string1 is an array of 4 characters that are filled up by the compiler with 4 characters ("asd" plus the string terminator) - you can change the contents of the array but you can't change the size.
So if you want a dynamically sized array of character strings you can do this:
#include <stdio.h> // printf
#include <stdlib.h> // malloc, realloc, free
#include <string.h> // strcpy, strdup
int main()
{
// make an array of 8 string pointers
int original_size = 8;
char **array = malloc(original_size * sizeof(char *));
// point each pointer to a string
// you don't have to do this all at once if you don't want to
for (int i=0; i<original_size; i++)
array[i] = malloc(40 * sizeof(char)); // max of 39 plus the terminator
// array[7] is already allocated so we can just use it as a string
strcpy(array[7],"asd"); // the last string that we malloced
// reallocate the array to be bigger
int new_size = 15;
array = realloc(array, new_size * sizeof(char *));
// array[14] is a pointer that doesn't point anywhere
// so we need to allocate space before filling it in
array[14] = strdup("qwe"); // points 3 characters plus the string terminator
printf("%s\n",array[7]);
printf("%s\n",array[14]);
// free the one we made with strdup
free(array[14]);
// free the 8 we malloced
for (int i=0; i<original_size; i++)
free(array[i]);
// now free the array we malloced and then realloced
free(array);
return 0;
}
Note: there is NO error checking in that program because I didn't want to mask the basic ideas - make sure you add error checking to any program you make
Try it at https://onlinegdb.com/XQeyOGd0C

How do I receive a char array in a C function?

I wish to split a "string" by the character ','.
The string holds a GPS NMEA encoded string, but that is of no matter.
My problem is that sometimes the parameter from the function that processes this char array is empty... Like nothing is in the array.
How should I correctly pass a "char string[]" to a function so that I may operate on a that parameter as I sent it(as a char array, not a char pointer to an array).
I also need to specify that I'm using mikroC for PIC.
Here is my code as of right now:
char* GPS_sateliti;
char CsatInView[] =
"$GPGSV,3,2,11,14,25,170,00,16,57,208,39,18,67,296,40,19,40,246,00*74";
GPS_sateliti = GrupeazaDupaVirgule(CsatInView, 2);
char* GrupeazaDupaVirgule( char deGasit[],int nrVirgule ){
int cVirgule = 1;
char* pch = strtok (deGasit,",");
while (pch != 0)
{
pch = strtok (0, ",");
cVirgule++;
if(nrVirgule == cVirgule){
break;
}
}
return pch;
}
The function that operates on the char array received as a parameter in debug mode, before entering the function the char array is fine, after entering it, it seems to be empty
It may be that I should receive a pointer to an array of chars??
Any sort of advice is welcome.
Thank you
How should I correctly pass a "char string[]" to a function so that I may operate on a that parameter as I sent it(as a char array, not a char pointer to an array).
You can't. A function parameter of an array type always decays as the corresponding pointer type.
There are two idiomatic solutions to this.
1. a sentinel:
The last value in the array is a special value that marks the end. This is done in C with strings. They always end with a \0 character, that is guaranteed not to occur inside the string. The function can search for that character to know where the data ends.
(Note: with this info I have to add I'm not sure what your problem is. If you pass an "empty string", as literally "", the \0 will be there, so you shouldn't have a problem)
2. explicitly passing the size:
instead of just
void foo(int bar[]);
you define a function
void foo(size_t barSize, int bar[]);
The caller knows the size of the array, so it can just pass it along.
With a pointer :
char* arr;
yourFunction(arr);
If you wish to initialize it before :
char* arr = malloc(51 * sizeof(char)); // Allocate a memory place of 50 because strings are null terminated in C
yourFunction(arr);
An other way to allocate memory to an array :
char* arr = calloc(50, sizeof(char)); // Allocate 50 memory place which size if the size of a char
With a string :
char arr[50];
char* ptr = arr;
yourFunction(ptr);
You have to know that it is impossible in C to know the size of an array when using pointer. The only thing you can do is to parse the size of the string as a parameter :
size_t size = 50;
char arr[size];
char* ptr = arr;
yourFunction(ptr, size);
If you wish to understand in detail how pointer works and how to iterate them, may be this post can help you. I think it is very interesting.
Globally, you iterate through an array via a pointer like this :
for ( int i = 0; i < size; i++)
printf("Current pointed value in the array : %c\n", ptr[i]); // or arr[i]
I guess you understand why giving the size of a pointed array as a parameter is important. Sometimes you can avoid using this parameter like this :
for ( int i = 0; i != '\0'; i++) // Because strings are null-terminated in C.
// Do something

C - what does while(*Table[i]) mean/do?

I need to add a string to an array and need some help figuring out what this means. Here is what I have:
#include <stdio.h>
#include <stdlib.h>
int insert(char *word, char *Table[], int n)
{
//*word is the string to be added, *Table[] is the array, n is
//the return value, which is the number of words in the array after adding *word
int i = 0;
while(*Table[i])
{
if strcmp(*Table[i], *word) == 0)
{
return n;
break;
}
}
}
I wrote this awhile ago and am just now revisiting it. I have no idea what while *Table[i] means, therefore I have no idea what the code that follows means. Also, this code is incomplete so don't bother telling me it won't add the string.
The * operator dereferences a pointer, and so does the [i].
Since Table is declared as char *Table[] this is the same as char ** in that it is a pointer to a pointer type (like a 2 dimensional array).
In this case it is apparent from the usage that Table is an array of strings (a string being an array of char (hence the array of arrays type)).
So Table[i] is a pointer to the i-th string in the array of strings, and then the * dereferences this again. What the author is doing here is looking for a NULL (zero) which follows the array of strings, which is clearly the method of determining the end of the array.

Running execvp from 2D array parameter

I'm attempting to run execvp using the data from a char[][] type (aka an array of strings). Now I know that execvp() takes a pointer to a string as its first parameter and then a pointer to an array of strings as its second - in fact I have even used it successfully before as such - however I cannot seem to get the correct combination of pointers & strings to get it to work out below - whatever I try is deemed incompatible!
Any help very grateful :) - I've removed my headers to compact down the code a bit!
struct userinput {
char anyargs[30][30]; //The tokenised command
};
int main() {
struct userinput input = { { { 0 } } }; //I believe is valid to set input to 0's
struct userinput *inPtr = &input; //Pointer to input (direct access will be unavailable)
strcpy(inPtr->anyargs[0], "ls"); //Hard code anyargs to arbitary values
strcpy(inPtr->anyargs[1], "-lh");
char (*arrPointer)[30]; //Pointer to an array of char *
arrPointer = &(inPtr->anyargs[0]);
printf("arrPointer[0]: %s, arrPointer[1]: %s\n", arrPointer[0],
arrPointer[1]);
printf("At exec case; ");
execvp( arrPointer[0], arrPointer);
perror("Command not recognised"); //Prints string then error message from errno
return 0;
}
There is no such thing as char[][] in C. execvp requires an array of pointers to const char. This can be written as either char * const * or char * const [].
You however have an array of 30-characters-long arrays, not an array of pointers. The two types are not compatible, not interchangeable, and not convertible one to another in either direction.
In this line
char (*arrPointer)[30]; //Pointer to an array of char *
you attempt to declare a pointer to an array of char*, incorrectly. What you have declared instead is a pointer to char[30], which is very different from what execvp expects.
The next line
arrPointer = &(inPtr->anyargs[0]);
purports to initialize a pointer to an array of char* with a pointer to char[30], which cannot possibly be correct even if you declare a pointer to an array of char*, because the right hand side of the assignment is not a pointer to an array of char*, it's a pointer to char[30] and no sequence of casts, indices, addresses and dereferences will turn one to the other.
An array of 30 pointers to char is declared like this:
char* arguments[30];
A dynamically-sized array of pointers to char is made like this:
char** arguments = calloc (nargs, sizeof(char*));
You need to use one of those if you want to call execvp.
In either case each pointer in the array of pointers must be initialized to point to an individual NUL-terminated character array (possibly to elements of your char[30][30] array) and the last pointer (one after all the argumenrs we want to pass) must be set to NULL. (I wonder how you expected to find a NULL in a char[30][30]).
The execvp() expects as second argument a char *const argv[]. This means an array of pointers to char. This is different from a char[30][30] which is represented in memory as 30x30 contiguous chars (so no pointer).
To solve this, define your structure
struct userinput {
char *anyargs[30]; //space for 30 char* pointers
};
You could as well define anyargs as char** and initalize if dynamically with (char**)calloc(number_of_args+1,sizeof(char*))
Later, assign directly the pointers:
inPtr->anyargs[0] = "ls"; //Hard code (or use strdup() )
inPtr->anyargs[1] = "-lh";
inPtr->anyargs[2] = NULL; // end of the argument list !!!
char **arrPointer; //Pointer to an array of char *
arrPointer = inPtr->anyargs;
Edit: Caution: "The array of pointers must be terminated by a NULL pointer.".

Resources