C++ How to use and pass a 3-dimensional char array? - c++

I'm trying to build a char array for storing the return value of a function. In the following function the data is stored in *****valv**. How to build a extern variable to access the data?
int credis_lrange(REDIS rhnd, const char *key,
int start, int end, char ***valv)
{
int rc;
if ((rc = cr_sendfandreceive(rhnd, CR_MULTIBULK, "LRANGE %s %d %d\r\n",
key, start, end)) == 0)
{
*valv = rhnd->reply.multibulk.bulks;
rc = rhnd->reply.multibulk.len;
}
return rc;
}
Solution:
char **elements;
int size = credis_lrange(this->redis,"object_2",600,603,&elements);
for (int i=0; i<size;i++) {
cout << "element: " << elements[i] << endl;
}
Thanks to everyone!

char ***element[size];
Is not exactly a 3D array, but an array of size elements of pointers-to-pointers-to-pointers to char.
Use any one of the following:
char e[ D1 ][ D2 ][ D3 ]; /* D1, D2, D3 are integral constants */
char *e[ D2 ][ D3 ];
char e[][ D2 ][ D3 ];
Also, you can pass it on by simply speficying e as the argument to your function.
On further reading, it appears that the parameter is not really a 3D array but a pointer to an array of C-style strings. Note, the syntax may be the same, the intent is different.
In that case, you'll need to do two things:
Specify the number of strings you want to store in the array
For each string
Allocate memory
Copy string data to the char array
And finally, you'll be passing in the address of this array of strings on to the credis_lrange function.

I only found one hit on Google for this, but it looks like the cr_sendfandreceive function allocates its rhnd->reply.multibulk.bulks member, so you don't actually have to pass it back (since you were passed rhnd in the first place).
If you want to copy it, then you would declare elements as a char** and pass its address (or use references), and then inside the method you would clone the bulks member and also each string in the array (in a loop).

In Arduino Studio environment, for MCUs programming like ST or ESP32 using PSRAM, one can allocate dynamic memory for a 3D multiarray of char array, sized 255, like so:
char*** 3d_array = (char***) heap_caps_malloc( sizeof(char)*255*(size_x*size_y*size_z), MALLOC_CAP_SPIRAM);
for X86/ X64 architectures a 3D multiaaray of char array, sized 255 can be declared as follows:
char*** 3d_array = (char***) malloc( sizeof(char)*255*(size_x*size_y*size_z));

Related

How to make a copy of a byte array in c code?

I have the address of the first char in my byte array, and it's size:
const char *rawImageBytes, int size
And I want to copy the content to a different byte array. and then modify that one a bit.
This is whay I am doing now:
LOGI("FrameReceived will reach here 1");
modifiedRawImageBytes = rawImageBytes;
jint sizeWH = width * height;
jint quarter = sizeWH/4;
jint v0 = sizeWH + quarter;
for (int u = sizeWH, v = v0, o = sizeWH; u < v0; u++, v++, o += 2) {
modifiedRawImageBytes[o] = rawImageBytes[v]; // For NV21, V first
modifiedRawImageBytes[o + 1] = rawImageBytes[u]; // For NV21, U second
}
But I don't get the correct colours, as if I would to this in Java, instead of c++.
And I am assuming this happens, because I just do modifiedRawImageBytes = rawImageBytes; instead of actually copying the whole byte array, so that it can start in memory from another address pointer.
A bit of a beginner with c, so I'm lost at this, can someone help me understand what is done wrong?
PS: I am assuming that, because even if I send the rawImageBytes and not the modifiedRawImageBytes, it will still be modified
This is because const char * is a pointer. This mean it represent an address. So you guessed right, the new variable represent the same datas.
To avoid this you should create a copy.
char modifiedRawImageBytes[size];
//if the pointer come from function's param don't redeclare it ;)
std::memcpy(modifiedRawImageBytes, rawImageBytes, size*sizeof(char));
This code will allocate a new char array and then memcpy will copy in the previous array data in the new array.
Note that you need to includecstdio

Variable size array in C++

This is interesting. I want to make a 2D array where one of the dimensions is a variable. Here is my code:
int main(void) {
const int rows = numlines("health.txt");
float data[rows][5] = {0};
readIntoArray(data, 5, rows, "health.txt");
return 0;
}
Line 3 "rows" is underlined with an error. It says: "Expression must have a constant value." Apparently it works for other people to use const in these situations. But mine might work differently because my variable is defined by a function. Here is that function:
int numlines(string filename) {
int number_of_lines = 0;
ifstream fin(filename);
string line;
while (getline(fin, line)) {
++number_of_lines;
}
return number_of_lines;
}
I have tried following other suggestions and making my code follow this format:
(Replace lines 2 & 3 of the first code block with this.)
int rows = numlines("health.txt");
float **data;
data = new float*[rows]; //The height is defined by the function
for (int i = 0; i < rows; i++) {
data[i] = new float[5]; //The width is 5
}
But then that causes an error on "data" in line 4 of the first codeblock. The error is Argument of type "float**" is incompatible with parameter of type "float (*)[5]". Here is the first line of the relevant function:
void readIntoArray(float data[][MAXCOLUMNS], int arrayX, int arrayY, string filename)
MAXCOLUMNS is #defined as 5.
How do I pass the 2D array into the function without creating an error?
I am not the most experienced in c++, so I might be missing something obvious.
There is a difference between:
const int rows = numlines("health.txt");
and
const int rows = 20;
In both cases the value of the variable cannot modified once it is initialzed. The difference is that in the first case, the value won't be known until run time while in the second case, the value is known at compile time.
In C++, an array can be declared using a variable only if its value is known at compile time.
That explains why you cannot use:
const int rows = numlines("health.txt");
float data[rows][5] = {0};
but you can use:
const int rows = 20;
float data[rows][5] = {0};
You can easily get around that issue by using an std::vector of std::vectors.
const int rows = numlines("health.txt");
std::vector<std::vector<float>> data(rows, std::vector<float>(5));
Since you know the size of the inner array, you can also you std::array. It will make the declaration a little simpler.
std::vector<std::array<float, 5>> data(rows);
In C++,you can use "std::vector< T >" to save your data as a variable size array.
Just learn how to use STL,it would simplify your works.
You can use alloca to implement the equivalent of a variable length array:
float (*data)[5] = (float (*)[5]) _alloca(rows * 5 * sizeof(float));
This will allocate local (stack) space and set data to point to the first row (with 5 columns) of a matrix of floats. The 5 can be replaced with a constant. You can then use data like a normal local matrix, data[ i ][ j ] ... . Depending on the compiler, the name may be alloca() instead of _alloca(), and the cast (float (*)[5]) may not be needed.
Since this is a local allocation, it's automatically freed when the function exits.

Is it possible to make an array of arrays?

I am writing a program to simulate a cache in c++ and am trying to copy addresses that are given in a file into an array. I am struggling to figure out how to copy an array into another array so that I can have an array of memory address arrays. I have read in the addresses into an array called "address" and I want my simulated cache to be an array called "L1_Cache". h is a counter that I am incrementing after I put an address into the L1_Cache. Also, cache size is going to be how many lines of addresses are available in my L1_Cache array, which will be decided by the user of the program. Below is the snippet where I am trying to put the array into the other array.
if(sizeof(L1_Cache) < cachesize)
strcpy(L1_Cache[][h], address);
they are defined as:
const char* address[10];
char* L1_Cache;
If anyone has any suggestions on how to copy one array into another array to make an array of arrays, let me know. I am not sure if anything I am doing is correct, but I am struggling to figure this out.
I want to compare new addresses that I am given to old addresses that are already in the L1_Cache array.
Yes, it is possible to make an array of arrays.
int a[3][3]; // a is an array of integer arrays
You have
a[0]; // this refers to the first integer array
a[1]; // this refers to the second array
Is the following what you are looking for?
#include <iostream>
#include <cstring>
int main()
{
char p[2][256];
strncpy(p[0], "This is my first address", 256);
strncpy(p[1], "This is my second address", 256);
std::cout << p[0] << std::endl << p[1];
return 0;
}
Yes. They are called multidimensional arrays.
They can have any number of dimensions.
For example:
int foo[3][3]; // initialize the 2 dimensional array of integers
foo[0][0] = 1; // change a value
foo[0][1] = 2; // change a value
foo[0][2] = 3; // change a value
foo[1][0] = 4; // change a value
foo[1][1] = 5; // change a value
foo[1][2] = 6; // change a value
foo[2][0] = 7; // change a value
foo[2][1] = 8; // change a value
foo[2][2] = 9; // change a value
for(int i=0;i<3;++i){ // display the 2d array
for(int j=0;j<3;++j){
cout<<foo[i][j];
}
cout<<endl;
}
What's happening:
Values are being assigned in a chart.
Think of it like writing a value on each point of a piece of paper.

Large Malloc Array data lost after successful assigning it to memory

I am trying to store large amount of data into multiple malloc array
I have three malloc array, two 2d char array and one int array. In a test case the array name are defined as:
cres=12163;
catm=41241;
matm = (char**) malloc(catm*sizeof(char*));
for(i=0;i<catm;i++)
matm[i]=(char*) malloc(5*sizeof(char));
mres = (char**) malloc(cres*sizeof(char*));
for(i=0;i<cres;i++)
mres[i]=(char*) malloc(5*sizeof(char));
mrin = (int*) malloc(cres*sizeof(int));
I read the data from a file. The data stored in these array if printed as it is stored in the these array is in right format. But when I try to retrieve data from the character arrays, after assigning value to the int array the character; array change the column length to 14 and the value is set to 8.50000000E-01.
I am using Linux Opensuse and g++ comiler.
Any Solution or alternate method to store large amount of data.
Sorry for all the confusion the blunder was on my part i was assigning the file-handling line pointer to all the values.
So matm is an array of char* with length catm. You then assign to its elements arrays of char of length 5. Then you do the same for res instead of atm.
Finally, you allocate and store in mrin an array of cres integers.
Almost certainly you are overflowing one of these arrays. You can use valgrind to figure out which, most likely automatically, by simply running valgrind ./a.out or whatever your program is called. It will print stack traces where memory errors occur.
You may simply have strings longer than 4 characters (plus the terminating null). You don't show the code where you populate the arrays.
Since you're using a C++ compiler, you should consider using C++ containers like std::vector<char> and std::string instead of raw C arrays which are error-prone as you have discovered.
OK, so I am going to take a crack at this... in C!
What you are making are arrays of pointers to char.
So two arrays of pointer to char, each holding 41241 pointers to char
One array holding pointers to int ( although why I have no idea since just declaring an array of int of size 12163 would do the trick.
Further you are declaring each entry on the char pointer array to be 5 chars which will hold a C style string of 4 bytes plus the null terminator.
char* strArray1 [41241] ;
char* strArray2 [41241] ;
int* intArray [12163] ;
for( int x=0 ; int < 41241;x++){
strArray1[x] = malloc(5*sizeof(char)) ;
strcopy("fred",strArray1[x]);
}
for( int x=0 ; int < 41241;x++){
strArray2[x] = malloc(5*sizeof(char)) ;
strcopy("Tom",strArray2[x]);
}
for(x=0;x<12163;x++){
inArray[x*] = rand() % 50 ;
}
for( int x=0 ; int < 41241;x++){
printf(" This entry = %s \n",strArray1[x]) ;
}
for( int x=0 ; int < 41241;x++){
printf(" This entry = %s \n",strArray2[x]) ;
}
for( int x=0 ; int < 12163;x++){
printf(" This entry = %i \n",intArray[x*]) ;
}
DO NOT try and get cute with C as it will bite you in the ass every time.

Is it possible to pass char[][] to a function requesting char**?

I am trying to call a function that takes char** as a parameter. Its job is to fill an array of strings (i.e. an array of char*). I know the max length of the strings, and I can pass the max number to fill as another parameter, so I was hoping to stack allocate it like this:
fill_my_strings(char** arr_str, int max_str); // function prototype
char fill_these[max_strings][max_chars_per_string]; // allocating chars
fill_my_strings(fill_these, max_strings); // please fill them!
Of course, I get the "cannot convert char[max_strings][max_chars_per_string] to char**" error.
I know this is some subtle (or not-so-subtle) problem with my understanding of the difference between arrays and pointers. I'm just not sure why it's not possible to pass this block of memory to something wanting a char** and have it fill in my stack-allocated chars. Could somebody please explain if this is possible, or if not, why not?
Is it possible to call a function like this without calling malloc / new?
The simple answer to your question is no; a two dimensional array is different than a pointer-to pointer type. Arrays decay to pointers to their first element, but pointers actually are that value.
The difference between these types is clear, if you cast both to char*
int x;
char *arr_pp[] = {"foo", "bar", "baz"};
char arr_2d[][4] = {"foo", "bar", "baz"};
char *cp = (char*)arr_pp;
for(x=0; x<3; x++)
printf("%d ", cp[x]);
printf("\n");
cp = (char*)arr_2d;
for(x=0; x<3; x++)
printf("%d ", cp[x]);
printf("\n");
The output (on my computer) is:
-80 -123 4
102 111 111
Where the first row is gibberish formed by the fact that I'm printing an address cast into bytes, and the second row is the ascii values of "foo".
In a function taking a char ** the compiler can't know to decay array types, which don't actually contain pointers.
Suppose you have n pointers to strings of m-1 maximum characters (m characters including the NULL).
So, in pure C:
sizeof(char[n][m]) will return n*m.
sizeof(char**) will return the size of a pointer in your architecture, probably 32 (if x86) or 64 (if x86_64).
char[n][m] actually allocates the n*m byte contiguously. char** allocates a single pointer. This pointer references a memory stripe of *n bytes. Each of these n pointers points to a memory stripe of m characters.
So, considering that sizeof(char) == u, if you declare char a[n][m], when you use a[i][j], the compiler understands *(a + i*m*u + j*u).
So, considering that sizeof(char *) == w, if you declare char **a, when you use a[i][j], the compiler understands ((a + i*w) + j*w).
Completely different data management.
The closes thing you could do to handle your special case is to create a char** variable, and populate it with the addresses of your stack allocated matrix.
char **tmp = malloc(max_strings * sizeof(char *));
int i;
for(i = 0; i < max_strings; i++){
tmp[i] = &(fill_these[i][0]); //you probably can't reference a char[][] with a single index - not confirmed
}
I am not sure why fill_my_strings() need a char** parameter. From your example, caller have already allocated the memory from stack. So using a char* should be OK.
But if you want to use char** or you can't modify the fill_my_strings() function, try following example code:
void fill_my_strings(char** arr_str, int max_chars_per_string, int max_strings)
{
for(int i = 0; i < max_strings; ++i)
{
//Make sure you have enough space
memcpy(*arr_str, "ABCD", sizeof("ABCD"));
*arr_str += max_chars_per_string;
}
}
char fill_these[max_strings][max_chars_per_string];
char* pointer = (char*)fill_these;
fill_my_strings(&pointer, max_strings, max_chars_per_string);
The obvious thing to do is build an index
In c use something like:
char string_list[num_strings][str_length];
// ...
char**index = calloc( (num_strings+1), sizeof(*index) ); // calloc insures NULL termination
for (int i=0; i<num_strings; ++i) {
index[i] = string_list[i]
}
In c++ prefer new[] to calloc;