I'm currently writing a project in C, and I need to be able to fill a 2D array with information already stored in another 2D array. In a separate C file, I have this array:
int levelOne[][4] =
{{5,88,128,0},
{153,65,0,0},
{0,144,160,20}}; //First Array
int levelTwo[][4] =
{{5,88,128,0},
{153,65,0,0},
{0,144,160,20}}; //Second Array
And in my main file, I have this variable which I'd like to fill with the information from both of these arrays at different points in my code. (This isn't exactly what I'm doing, but it's the general gist):
#include "arrayFile.c"
void main()
{
int arrayContainer[][4] = levelOne;
while (true)
{
func(arrayContainer);
if(foo)
{
arrayContainer = levelTwo;//Switches to the other array if the conditional is met.
}
}
}
I know this method doesn't work - you can't overwrite items in arrays after they're instantiated. But is there any way to do something like this? I know I'll most likely need to use pointers to do this instead of completely overwriting the array, however there's not a lot of information on the internet about pointers with multidimensional arrays. In this situation, what's best practice?
Also, I don't know exactly how many arrays of 4 there will be, so I wouldn't be able to use a standard 3D array and just switch between indexes, unless there's a way to make a 3D jagged array that I don't know about.
Given the definitions you show, such as they are, all you need is memcpy(arrayContainer, levelTwo, sizeof LevelTwo);.
You should ensure that arrayContainer has sufficient memory to contain the copied data and that LevelTwo, since it is used as the operand of sizeof, is a designator for the actual array, not a pointer. If it is not, replace sizeof LevelTwo with the size of the array.
If you do not need the actual memory filled with data but simply need a way to refer to the contents of the different arrays, make arrayContainer a pointer instead of an array, as with int (*arrayContainer)[4];. Then you can use arrayContainer = levelOne; or arrayContainer = levelTwo; to change which data it points to.
Also, I don't know exactly how many arrays of 4 there will be, so I wouldn't be able to use a standard 3D array and just switch between indexes, unless there's a way to make a 3D jagged array that I don't know about.
It is entirely possible to have a pointer to dynamically allocated memory which is filled with pointers to arrays of four int, and those pointers can be changed at will.
Related
I started learning C and wanted to try some of the Swift-C interoperability.
I have a small C function which reads me a file and concatenates some useful letters into a char* variable. After some testing, I cannot find a way to pass my obtained char* data back to swift. I have written a small dummy code to illustrate what I am trying to achieve.
var letters: [CChar] = []
functionWithArray(&letters)
print("Back in swift: \(letters)")
And the C function is:
void functionWithArray(char* letters) {
int arrayLenght = 5;
int testLenght = 10; // Expand array to this value (testing)
int currentArrayPosition = 0; //Keep track of the assigned values
letters = malloc(sizeof(char)*arrayLenght);
while (currentArrayPosition < testLenght) {
if (currentArrayPosition == arrayLenght) {
arrayLenght++;
letters = realloc(letters, sizeof(char)*arrayLenght);
}
letters[currentArrayPosition] = *"A";
++currentArrayPosition;
}
printf("End of C function: %s\n", letters);
}
I get this as an output:
End of C function: AAAAAAAAAA
Back in swift: []
Program ended with exit code: 0
As you can see, inside the C function I've got the desired result, but back in swift I could not find a way to obtain the modified array. I do not return letters directly with the function because I need to return more values from that function. I'm new to C so please be kind.
There are two main issues with your approach here — one in C and one in Swift:
In C, function parameters are passed by value, and are effectively mutable local variables. That means that when functionWithArray receives char *letters, letters is a local variable containing a pointer value to the buffer of letters in memory. Importantly, that means that letters is assignable, but not in the way that you think:
letters = malloc(sizeof(char)*arrayLenght);
allocates an entirely new buffer through malloc, and assigns the newly-created pointer value to your local letters variable. Before the assignment, letters is a pointer to the buffer you were getting from Swift; after, to an unrelated buffer in memory. These two buffers are completely unrelated to one another, and because letters is just a local variable, this assignment is not propagaged in any way outside of the function.
Note that this is just a rule of C: as you learn more C, you'll likely discover that in order to assign a variable from inside of a function to outside of a function, you need to wrap the variable in another layer of pointers and write through that pointer (e.g., you would need to receive char **letters and assign *letters = malloc(...) to have any effect on a variable being passed in — and the variable couldn't be passed in directly, but rather, its address would need to be passed in).
However, you can't generally make use of this fact because,
The implicit conversion of an Array<T> to an UnsafeMutablePointer<T> (e.g. [CChar] → UnsafeMutablePointer<CChar> in Swift == char * in C) does not allow you to assign an entirely new buffer to the array instance. You can write into the contents of the buffer by writing to pointer values, but you cannot allocate a new block of memory and reassign the contents of the array to that new block
Instead, you'll need to either:
Have functionWithArray return an entirely new array and length from C — you mention this isn't possible for functionWithArray specifically because of the other values it needs to return, but theoretically you can also create a C struct which wraps up all of the return values together and return one of those instead
Rewrite functionWithArray to receive an array and a length, and pre-reserve enough space in the array up-front to fill it appropriately:
var letters: [CChar] = []
letters.reserveCapacity(/* however much you need */)
functionWithArray(&letters, letters.capacity)
In functionWithArray, don't reassign letters, but instead fill it up to the capacity given to you with results. Of course, this will only work if you know in Swift ahead of time how much space functionWithArray will need, which you might not
Alternatively, you can also use Array.init(unsafeUninitializedCapacity:initializingWith:) to combine these operations by having Array preallocate some space, and you can pass in the inout UnsafeMutableBufferPointer<CChar> to C where you can allocate memory if you need to and assign to the buffer pointer, then write out to the inout Int how many array elements you allocated and initialized. This does also require a capacity, though, and is a more complicated solution
Of these two approaches, if functionWithArray really does need to dynamically reallocate memory and grow the buffer, then (1) is likely going to be easier.
before you mark this as a duplicate please notice that I'm looking for a more general solution for arrays of arbitrary dimensions. I have read many posts here or in forums about making 2D or 3D arrays of integers but these are specific solutions for specific dimensions. I want a general solution for an array of any dimension.
First I need to have a type of intlist as defined below:
typedef struct{
int l // length of the list
int * e // pointer to the first element of the array
}intlist;
this actually fills the gap in C for treating arrays just as pointers. using this type I can pass arrays to functions without worrying about loosing the size.
then in the next step I want to have a mdintlist as multidimensional dynamically allocated arrays. the type definition should be something like this:
typedef struct Mdintlist{
intlist d // dimension of the array
/* second part */
}mdintlist;
there are several options for the second part. on option is that to have a pointer towards a mdintlist of lower dimension like
struct Mdintlist * c;
the other options is to use void pointers:
void * c;
I don't know how to continue it from here.
P.S. one solution could be to allocate just one block of memory and then call the elements using a function. However I would like to call the elements in array form. something like tmpmdintlist.c[1][2][3]...
Hope I have explained clearly what I want.
P.S. This is an ancient post, but for those who may end up here some of my efforts can be seen in the Cplus repo.
You can't! you can only use the function option in c, because there is no way to alter the language semantics. In c++ however you can overload the [] operator, and even though I would never do such an ugly thing (x[1][2][3] is alread y ugly, if you continue adding "dimensions" it gets really ugly), I think it would be possible.
Well, if you separate the pointers and the array lengths, you end up with much less code.
int *one_dem_array;
size_t one_dem_count[1];
int **two_dem_array;
size_t two_dem_count[2];
int ***three_dem_array;
size_t three_dem_count[3];
This way you can still use your preferred notation.
int num_at_pos = three_dem_array[4][2][3];
I am to read in several values from the user and store those in an array. Then I need to create an array which is big enough to store all those values. Using some functions I wrote I sort/lsearch/bsearch through the array for given values.
I already have my program written and everything, but for a static array implementation. I am sort of getting confused on where to actually use the dynamic array.
It makes sense to use it when the user starts entering values, since I can't assume how many values he enters, so the array needs to be big enough to hold it. It also makes sense (Sort of) to use it when I am creating a big enough array that can hold all the value (Acts as a copy of the first array).
I'm not asking for any code, everything is done but on a static approach. I am just trying to visualize where I would need to use darrays here. My thoughts are:
When the user first enters the values
When i copy arr1 into a new arr2 that needs to be big enough to hold all of arr1's values.
Am I right or wrong on this?
Start by using malloc or calloc to allocate an array of some known starting size, and keep track of the current capacity in a variable.
As you're reading values in, if your array isn't big enough, then user realloc to double the size of the array.
The best solution is not to copy the entire array each time a user inputs a value. The demands on malloc and free will be heavy, and get worse with larger arrays.
You need to calculate the size of your array with "number of elements as the input
int* array = newArray(10);
int* newArray(int size) {
return malloc(size * sizeof(int));
}
Keep in mind that an int* is an array, so you can still do array[3]. But, if you centralize the storage of number of used elements and the current size, you can allocate a few elements and only grow when the available elements are exhausted.
struct DynamicIntArray {
int used;
int size;
int* storage
};
void add(struct DynamicArray* array, int value) {
if (used < size) {
(*array).storage[used] = value;
used++;
} else {
int newSize = size+10;
int* newStorage = (int*)malloc(newSize*sizeof(int));
int* oldStorage = (*array).storage;
for (int i = 0; i < size; i++) {
newStorage[i] = oldStorage[i];
}
(*array).storage = newStorage;
(*array).size = newSize;
free(oldStorage);
}
}
with such an example. You should be able to write the newDynamicIntArray(...) function and the freeDynamicIntArray(struct DynamicIntArray* array) function and any other methods you care about.
I think you ask the wrong question.
The question is:
Is a dynamic array (a contiguous block of memory) the proper data structure to hold and process the data in your application?
There is only one especially useful application for arrays and that is as associative array, which means that the array index itself has a meaning and can be used to retrieve the correct contents you are searching with an effort of O(1).
In example, a list of track runners could be stored in an array, where the array index equals the track number. This is the perfect data structure if you want to visualize the name of the runners per track. It's a terrible data structure if you want to alphabetically sort the names of all runners.
But according to your application description, the array index has no meaning for you. This is an indication that an array is not the best choice.
If you are not sure how many entries inserted at runtime i suggest you to use linked list data structure. It will save your memory usage.
I got strucure
typedef struct
{char *cells;}
Map;
and cells suppose to be pointer to array of rows(in rows are integers on every position).
I don't know how to access for example to number on 3. position in 2. row.
I have stared with some array[3][3], but I don't know how to connect them with this struct.
I tried
Map nextmap;
nextmap.cells[0] = array[0][0];
But I got only first number, which is clear. How can I get to other positions?
Thanks in advance.
EDIT: renaming the structure ..
.
When you did Map nextmap;, you created an uninitialized Map struct. When you did nextmap.cells[0] = array[0][0]; you dereferenced (i.e. followed) the uninitialized pointer, and stored a value at the random memory it points at.
If you want to initialize the cells structure, you can do something as simple as nextmap.cells = array[0]; That will cause nextmap.cells to point at array. Note that it's not copying the contents; just pointing at them. That means that if you change the values through cells, you'll be modifying the values in arrays.
(Also, using 'new' as a variable name is perfectly acceptable in C, but you're likely to confuse any C++ programmers reading your code, since 'new' is an operator in that language.)
new now changed to nextmap in question
Edited to correct the type mismatch in nextmap.cells assignment.
Given an array char array[][NumberOfColumns] (the first dimension is irrelevant and is omitted here; it would be needed when the array is defined), you can set a pointer to the first element of the array with:
nextmap.cells = &array[0][0];
Then you can access an element in the array, array[i][j], by calculating its position within the array, with either of these two expressions:
*(nextmap.cells + i*NumberOfColumns + j)
nextmap.cells[i*NumberOfColumns + j]
Two-dimensional arrays generally ought to be addressed as two-dimensional arrays. Calculating the position manually is poor practice if done without good reason. If this school assignment did not have a good reason for this, then it is a bad assignment.
First of all new is not a good name for a variable.
new now changed to nextmap in question
Second of all in your case cells should be a double pointer, like this
char ** cells;
Or a pointer to a 2D array, like
char (*cells)[N][N];
where N is a constant you want to use.
I am having a VB application request a list of users from a C DLL:
VB will ask the DLL how many users there are, and then initialize an array to the appropriate size.
VB will then pass its array by reference to a DLL function, which will fill it with usernames.
I started writing the C function like this: foo(char **bar); which would be treated as an array of strings. But then I realized, I'm going to make each item in the array point to a different C-string (the char *username in the struct userlist linked list) rather than modify the data already being pointed to. The array of arrays is being passed by value: a copy of a list of addresses, so the addresses point to the original data, but modifying the addresses in that copy won't change the list of addresses of the caller (I think, anyways). So, should I be declaring it foo(char ***bar);? This would be a pointer to the array of strings, so that if I change the strings that array is pointing to, it will modify the array of strings the caller (VB) is using....right?
This is my usage so far (haven't tested it yet... I'm still just coding the DLL as of yet, there's no VB front-end to call it thus far)
EXPORT void __stdcall update_userlist(char ***ulist){
int i = 0;
userlist *cur_user = userlist_head; //pointer to first item in linked list
for(; i < usercount_; ++i){
*ulist[i] = cur_user->username;
cur_user = cur_user->next;
}
}
In general it's not simple to do what you're asking, because VB just doesn't understand C-style ASCIIZ strings and arrays.
If your DLL is not expecting a VB SafeArray of BSTR, you're going to have some difficulty populating it.
It would be simple to have VB pass in an array of Long (C int) by reference to the first element, and you could fill that with the pointers to individual strings. The VB side could copy them to VB strings. But in that case, who disposes of the C strings, and when?
If you create the VB array and fill it with pre-sized strings, you'll still have to deal with a SafeArray on the C side, because you can't pass a single VB string array element by reference and expect to find the remaining strings contiguous to it in memory.
The best, safest method is to have your DLL create a SafeArray of so-called 'Ansi BSTR', and declare the function in VB as returning an array of strings. Then you don't need two calls, because the array bounds will tell the whole story.
===== edit =====
When VB passes a string array to a Declared function it does some voodoo behind the scenes. It first converts all the strings from Unicode to a bastard form commonly known as 'Ansi BSTR'. To C, these look like and can be treated as ASCIIZ or LPSTR except that you can't create or lengthen them in the normal C way, you can only fill them in. On the C side, the passed array looks like ppSA (SAFEARRAY**). The Ansi BSTR are a series of pointers referenced by the pData member of the SafeArray.
You absolutely cannot pass a single string from the array (as char*) and expect to find the rest of the strings contiguous to it in memory. You have to pass the array itself and manipulate it using the SafeArray API (or knowledge of the SA structure).
That's why the best option overall is to do all of this directly in the DLL. Create the array using SafeArrayCreate, then create Ansi BSTRs using SysAllocStringByteLen and place those strings (which are BSTR, so a 4-byte pointer) into the array slots. On return, VB does its voodoo and converts the strings to Unicode for you.
In VB your function would be Declared as returning a String().
two asterixes is the way to go.
char* // is a pointer to a char
char** // is a pointer to a char pointer
char*** // is a pointer to a pointer to a char pointer - e.g. multi-dimensional array (err...)
I've confused myself :)
So let me get this straight. Your function fills in an array of strings from data contained in a linked list ?
If you know the size of the list beforehand, you can just pass a char **, but if you do not know the size and need to be able to grow the list, you will need a char ***.
From looking at your code, you seem to already know the length, so you just need to allocate an array of the correct length before you call the function. Here is an example:
void update_userlist(char **ulist)
{
int i = 0;
userlist *cur_user = userlist_head;
for(; i < usercount_; ++i)
{
ulist[i] = cur_user->username; // I am assuming that username is a char *
cur_user = cur_user->next;
}
}
// This sets up the array and calls the function.
char **mylist = malloc(sizeof(char*) * usercount_);
update_userlist(mylist);
Update: Here is the difference between the various levels of pointers:
void func1(char *data)
This passes a copy of a pointer to a C string. If you change the pointer to point to a different string, the calling function will still point to the original string.
void func2(char **data)
This passes a copy of a pointer to an array of pointers to C strings. You can replace the pointer to any string in the array and the calling function's array will be changed because it has not made a copy of the array, it only points to the caller's array.
void func3(char ***data)
This passes a pointer to a pointer to an array of pointers to C strings. With this, you can completely replace the entire array. You would only need this level of indirection if you need to grow the array since C arrays cannot be re-sized.