I am trying to wrap my head about the concept of 2-dimensional arrays (of structs) in C
Say I have the following definition:
typedef struct group group;
struct group {
int members;
int neighbours;
char color;
};
#define NUM_CELLS 10
With the following function that is supposed to copy some data from a single array to a multidimensional array:
void test_mgroup_arr(group clusters[][NUM_CELLS],group tests[NUM_CELLS], int num_groups) {
int i;
int j = 0;
for (i = 0; i < num_groups; ++i)
clusters[i][j] = tests[i];
}
This is called like:
int num_groups = 5;
group clusters[NUM_CELLS][NUM_CELLS];
group tests[NUM_CELLS];
tests[0].members = 101;
tests[0].neighbours = 111;
tests[1].members = 102;
tests[1].neighbours = 112;
tests[2].members = 103;
tests[2].neighbours = 113;
tests[3].members = 104;
tests[3].neighbours = 114;
tests[4] = tests[3];
test_mgroup_arr(clusters, tests, num_groups);
I expect the code in the function to copy the 5 items from the test array to the right place in the multi-dimensional array. However, this does not work as expected, and even segfaults in some cases.
How is this not correct? What would be the right way of copying a struct from a 1dim array to a 2 dim array?
I do not see an issue in how you are passing the array or accessing it. The code actually looks right, and gives me the right results. Note:
for(i = 0; i < num_groups, ++i)
clusters[i][j] = tests[i];
Lets say the address of:
clusters[0][0] is 0x0047F7EC
clusters[1][0] is 0x0047F864
clusters[2][0] is 0x0047F8DC
sizeof(group) = 0xC * 0xA (num of groups) = 0x78
So you can see the math works out here.
j always == 0, so what's i doing?
The address of clusters+i is:
0x0047F7EC for i=0
0x0047F864 for i=1
0x0047F8DC for i=2
Exactly what you'd expect. When I get out of test_mygroup_arr I get values of clusters[0][0], clusters[1][0], clusters[2][0], clusters[3][0], clusters[4][0] are set to the values in tests[0], tests[1], tests[2], tests[3], tests[4] respectively.
That's what you were going for correct?
Did you try printing out the addresses to see what was happening? Is there more to your code that you're not showing? I'm wondering if something else is the cause of your seg fault.
I assume you're using a C99 Compiler?
Note: My test of your code that worked fine was only and exactly what you posted.
int main()
{
int num_groups = 5;
...
test_mgroup_arr(clusters, tests, num_groups);
return 0;
}
Actually to pass array as parameter you have to pass pointer on it`s first element, this is how compiler expects it, so instead of
void test_mgroup_arr(group clusters[][NUM_CELLS],group tests[NUM_CELLS], int num_groups)
use
void test_mgroup_arr(group (*)[NUM_CELLS],group tests[NUM_CELLS], int num_groups)
Related
I'm working on a CS assignment, where I have to use p_threads to compute an array's prefix sum. The professor told us to use the Hillis and Steele algorithm. I found some pseudocode on wikipedia (here), specifically:
I'm a little stuck on implementing this in real code. The way our program is supposed to work, the user passes in an array through a file or stdin, then the next 2 arguments are the size of the input array, and how many threads we need to use.
So, I assume "n" in this picture is "amount of threads we need to use".
Then, I'm not sure what the notation on the x's mean. Wikipedia says "In the above, the notation ... means the value of the jth element of array x in timestep i." but...what? How do I implement this "timestep"? I assumed that it meant: "do j to the i+1th power, then find that index element in array x". With that assumption, I wrote this code:
void scan(int numThreads, int* vector, pthread_t* threads){
for(int i = 0; i < logbase(numThreads, 2); i++){
for(int j = 0; j < numThreads - 1; j++){
// create a thread here to perform parallel()
int* args = calloc(3,sizeof(int));
args[0] = i;
args[1] = j;
args[2] = *vector;
pthread_create(&threads[j], NULL, parallel, (void*)args);
free(args);
}
}
}
// each thread runs this function
void* parallel(void *arg){
int i = ((int*)arg)[0];
int j = ((int*)arg)[1];
int* vector = ((int**)arg)[2];
if(j < pow(2, i)){
// store current element (jth element of array x to the power of i)
// in the jth element of array x to the power of i + 1
vector[(int)pow(j, i+1)] = vector[(int)pow(j, i)]; // ISSUE IS HERE
}
else{
// store current element plus element at j-2^i ^i in current^i+1
vector[(int)pow(j, i+1)] = vector[(int)pow(j, i)] + vector[(int)pow(j -
pow(2, i), i)];
}
return NULL;
}
The line commented "ISSUE IS HERE" segfaults. I can step through in gdb and figure out why it's segfaulting myself, but I want to know if I'm even doing this right. This is my first time doing anything with multithreading. We're also supposed to create our own barriers using a combination of locks and condition variables, but I'm not even sure how to do that.
Also, some code isn't pictured, such as my "logbase" function and the function that reads in the input array. I know those work fine.
Thank you for your time.
You problem is here, you are trying to pass a pointer to vector
args[2] = *vector;
but instead you just pass in the first element and then treat it as a pointer after wards, that wont work. You need to pass in the pointer but that probably wont fit in the space you have reserved.
If you have to pass the args like that (as opposed to simply creating some static globals) then you should do this
struct args_t
{
int i;
int j;
int * vector;
};
then
struct args_t *args = malloc(sizeof(struct args_t));
args->i = i;
args->j = j;
args->vector = *vector;
pthread_create(&threads[j], NULL, parallel, (void*)args);
then add corresponding code at the receiving side
I'm sure this question has been asked before, but I've been searching pretty constantly for the last 2 days and can't solve this, so I'm hoping someone will help me out.
For my C assignment, we are supposed to receive each function parameter as a pointer. One of the values passed is a 2D char array, and for the last 48+ hours, I haven't been able to find out how to properly do this in my book, notes, instructor slides, etc. and actually make it work.
Simplified code of what I'm trying to accomplish
void main(){
/*
This is the value being passed. The first dimension has a size of 1000,
to account for 1000 different sorted people. Second dimension is an
array that holds the actual name, with a max name length of 25.
*/
char names[1000][25] = {'\0'};
read_files(names);
}
void read_files(char* names){
char newName1[4] = "mary";
char newName2[4] = "anna";
for(int i = 0; i < 5; i++){
names[0][i] = newName1[i];
}
for(int i = 0; i < 5; i++){
names[1][i] = newName2[i];
}
}
Basically, I'm trying to get names[0][x] to have x = "mary", and names[1][x] to have x = "anna".
(Or, more literally, names[0][0]= 'm', names[0][1]= 'a', etc.)
Unfortunately I can't get the passing right. The closest I've gotten is to have it assign one name to names, but not anymore.
Any help with this would be fantastic. There's actually quite a few classmates I'm working with who are all stumped on this. I'm sure its easy for experienced guys, but we just haven't gotten good instruction on how to do it and I can't find many specific examples that address this exact issue.
As I said, our instructor specifically wants function arguments to be pointers.
EDIT
Good info so far, I was very close to a few of these examples. I'll give them a shot and see what works.
You would have to define read_files as this:
void read_files(char (*names)[25]) {
char newName1[5] = "mary";
char newName2[5] = "anna";
for(int i = 0; i < 5; i++){
names[0][i] = newName1[i];
}
for(int i = 0; i < 5; i++){
names[1][i] = newName2[i];
}
}
Because you need to pass a pointer to an array of char[25]. A two
dimensional array cannot be converted into a double-pointer or a single pointer.
Note also that newName1 and newName2 must be arrays that can hold 5 elements. In C a
string is a sequence of characters that ends with the '\0'-terminating byte.
That means that for a string of length n, you need a char array of length
n+1, because you need the extra byte for the '\0'-terminating byte.
Also the better way of copying strings is strcpy or strncpy. strncpy is
more safe than strcpy because you limit the amount of bytes to be copied, thus
avoiding a buffer overflow. But strncpy might not write the '\0'-terminating byte
if there is not enough room.
Instead of:
for(int i = 0; i < 5; i++){
names[0][i] = newName1[i];
}
use this:
strcpy(names[0], newName1);
Or the strncpy way:
strncpy(names[0], newName1, sizeof names[0]);
names[0][sizeof(names[0]) - 1] = 0; // making sure to add the \0 byte
Also bear in mind, that the correct definition of the main function can be
only one of these:
int main(void);
int main(int argc, char **argv);
int main(int argc, char *argv[]);
#include <stdio.h>
void read_files(char* names){
char newName1[4] = "mary";
char newName2[4] = "anna";
for(int i = 0; i < 5; i++){
names[i] = newName1[i];
}
int offset = 25;
for(int i = 0; i < 5; i++){
names[i + offset] = newName2[i];
}
}
void main(){
/*
This is the value being passed. The first dimension has a size of 1000,
to account for 1000 different sorted people. Second dimension is an
array that holds the actual name, with a max name length of 25.
*/
char names[1000][25] = {'\0'};
read_files(names[0]);
printf("%s %s", names[0], names[1]);
}
In memory a 2d array is still a 1d block with fancy addressing. So you could have an offset variable and just add it on to every name like I have done here
My issue is with nums3 array and why the last for-loop actually prints expected results. The nums3 array as I understand it contains an array of pointers to the struct but these pointers have not yet been initialized to any specific instance of a struct. But in this for-loop I can assign values and see the expected results display.
Also, I've read that with the pointer returned by malloc I can use the [index] after the pointer and iterate over the allocated memory. I assume this feature is using the fact it has a type multiplied by some value and it does the division automatically to know how this block of memory is split up and therefore how far to advance to the next index. But I'm still confused as to why I'm getting expected results on that last for-loop when I haven't initialized or pointed those pointers to anything specific.
I know that if I were to add ** and change the to -> then I could operate on those pointers directly, but with the code now I'm able to use the . operator to access structure members. So, without the ** in the nums3 malloc line, what exactly does the pointer returned from malloc return?
#include <stdio.h>
#include <stdlib.h>
#define ARRAY_MAX 5
int main(void)
{
struct number {
int num1;
int num2;
int num3;
};
struct number n;
n.num1 = 5;
printf("n.num1: %d\n", n.num1);
n.num2 = 6;
printf("n.num2: %d\n", n.num2);
n.num3 = 7;
printf("n.num3: %d\n", n.num3);
struct number nums1[5];
struct number* nums2 = malloc(sizeof(struct number) * ARRAY_MAX);
struct number* nums3 = malloc(sizeof(struct number*) * ARRAY_MAX);
int x;
for(x = 0; x <= 5; x++) {
nums1[x].num1 = x;
nums1[x].num2 = x;
nums1[x].num3 = x;
}
int y;
for(y = 0; y <= ARRAY_MAX; y++) {
nums2[y].num1 = x;
nums2[y].num2 = x;
nums2[y].num3 = x;
}
for(y=0; y<=ARRAY_MAX; y++) {
nums3[y].num1 = y;
nums3[y].num2 = y;
nums3[y].num3 = y;
printf("%d ", nums3[y].num1);
printf("%d ", nums3[y].num2);
printf("%d \n", nums3[y].num3);
}
Here is a simpler test case of my question:
#include <stdio.h>
#include <stdlib.h>
#define MAX 5
int main(void)
{
struct number {
int num1;
};
struct number* n = malloc(sizeof(struct number*) * MAX);
int i;
for(i=0; i<MAX; i++) {
n[i].num1 = i;
printf("%d\n", n[i]);
}
free(n);
}
Result of running this code:
jason smith#jasonS-pc ~/src/c
$ ./a.exe
0
1
2
3
4
jason smith#jasonS-pc ~/src/c
$
Questions:
How does n[i] work with n being the pointer returned from malloc? How does C know what to do with n[i]? How does C know how to get to n[i+1]? Does it look at what sizeof() is being called on and divide by however many times it is multiplied and use that result to know where the next cell starts?
Why does n[i].num1 = i; even compile? If all I have done is specify a block of memory containing size for x number of pointers to the struct (pointers which would be smaller than the size of the struct itself) and certainly have not initialized anything to point to an actual instance of this struct. Why isn't this a syntax or some other compiler generated error? What exists at cell n[i] that .num1 is working on? Doesn't n[i] right now just contain a pointer without a valid address since it's not yet initialized? How do we go from that to n[i].num1 = i? Is it valid syntax to do "some memory address".num1 = "some value"?
I understand this is not the correct way to do this, and you all have provided great information, but I'm still puzzled as to why this code even compiles. It just doesn't make sense to me.
In general, if you access memory incorrectly you cannot expect anything. You can't expect to get the right answer, and you can't expect to get the wrong answer. You can't expect your program to crash and you can't expect it to run. Again, it can do anything.
The error here is that you allocated an array of pointers but then chose the wrong type to hold the result.
// This is wrong!
struct number* nums3 = malloc(sizeof(struct number*) * ARRAY_MAX);
You want this:
struct number **nums3 = malloc(sizeof(struct number*) * ARRAY_MAX);
// ^^
Or really, this way is better:
struct number **nums3 = malloc(sizeof(*nums3) * ARRAY_MAX);
Then you have an array of (uninitialized) pointers to play with. For example,
for (int i = 0; i < ARRAY_MAX; i++) {
nums3[i] = malloc(sizeof(*nums3[i]));
nums3[i]->num1 = i;
nums3[i]->num2 = i;
nums3[i]->num3 = i;
}
or...
for (int i = 0; i < ARRAY_MAX; i++) {
nums3[i] = &nums2[i];
}
Whatever you want.
(We're pretending here that malloc() doesn't return NULL which is not guaranteed.)
You are correct by saying you are not allocating enough space as sizeof(struct number) = 12 while sizeof(struct number*) = 8
Malloc finds a free memory according to the size you asked and (if successful) returns you a pointer to the first address (this is virtual memory). If you exceed the size created you enter the realm of unexpected behavior. Meaning you either will be able to write and read data from the memory or you won't and even if you manage to do that, you can accidentally overwrite areas in memory storing other data.
In this case, although printing passed with no special behavior, when you try to free(nums3) you will get an error.
Also, if you will reverse the order of nums2 and nums3 declaration and print nums2 after nums3 loop, you will probably be able to see this corruption of data.
Hope this is helpful
Consider a simple struct, Foo, which contains a pointer to some other strucrt, Baz. and a two-dimensional array, (stack-allocated):
Foo arr[ARR_SIZE][ARR_SIZE];
Next, consider a function which mallocs (in the heap, obviously) a memory for a new 2d-array of Foos. A code snippet:
Foo** arr_copy = malloc(sizeof(Foo*) * ARR_SIZE);
for (int i = 0; i < ARR_SIZE; i++)
{
arr_copy[i] = malloc(sizeof(Foo) * ARR_SIZE);
}
for (int i = 0; i < ARR_SIZE; i++)
{
for (int j = 0; j < ARR_SIZE; j++)
{
arr_copy[i][j].baz = malloc_baz();
}
}
Now, in my project I have various of functions which need to handle both the original array (stack allocated) and the copy (which is heap-allocated)
Problem is, things got quirky (memory looks corrupted) when I passed the copy to some function which iterate the 2d-array and print some info.
Basically, I know that there should not be a difference between: void fun(Foo** arr) to void fun(Foo arr[ARR_SIZE][ARR_SIZE]) but both ways were problematic.
So my question is, how can a function handle both arrays, stack/heap allocated?
Thanks.
If you try to do this in c or c++:
int test[][];
you will get this error:
error: declaration of 'test' as multidimensional array must have bounds for all dimensions except the first
This is because test is not in fact a double ponter as you'd expect. But the compiler converts it into a single block of data. And this:
int test[XSIZE][YSIZE];
int n = test[x][y];
will be converted into something like this:
int test[XSIZE*YSIZE];
n = test[YSIZE*x + y];
For solving this, i think #BLUEPIXY already put a solution in the comments.
Also, have a look at this question.
Suppose I declared an array as following:
int myArr = [someSize];
Now I put n elements (where n is not known exactly but n < someSize) in it like this
myArray[0] = 12;
myArray[1] = 23;
and so on .....
Now I want to know is there any way to find out exactly how many elements have been entered by the user.
You can't get any such information from the array. If you need it, you'll want to record it. When I've needed this, I've usually used something like:
struct myArray_t {
size_t next_element;
int arr[somesize];
};
When you create this, you set next_element to 0, and to add an element, you use something like myArr.arr[myArr.next_element++] = whatever;
No, if that's all you have you can't figure it out. C does not internally store the number of array elements written to.
If you know that there is some value that can't be put into the array (i.e. it is checked and disallowed beforehand), then you can initialise every element of the array to that, and then just do a count. e.g. if the array is initialised to -1:
int count = 0;
for (i = 0; i < someSize; i++) {
if (myArr[i] != -1) count++;
}