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
Related
I wanted to create a function that deletes from an array of segments the ones that are longer than a given number, by freeing the memory I don't need anymore. The problem is that the function I've created frees also all the memory allocated after the given point. How can I limit it, so that it frees just one pointer without compromising the others?
Here is the code I've written so far:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
typedef struct
{
double x1;
double y1;
double x2;
double y2;
} Segment;
double length(Segment* s)
{
return sqrt(pow(s->x1 - s->x2, 2) + pow(s->y1 - s->y2, 2));
}
// HERE IS THE PROBLEM!!
void delete_longer(Segment* as[], int n, double max_len)
{
for(int i = 0; i < n; i++)
{
if(length(as[i]) > max_len)
{
as[i] = NULL; // Those two lines should be swapped, but the problem remains
free(as[i]);
}
}
}
int main()
{
const int SIZE = 5;
Segment** arr = (Segment**)calloc(SIZE, sizeof(Segment*));
for(int i = 0; i < SIZE; i++)
{
arr[i] = (Segment*)malloc(sizeof(Segment));
}
srand(time(0));
for(int i = 0; i < SIZE; i++)
{
arr[i]->x1 = rand() % 100;
arr[i]->x2 = rand() % 100;
arr[i]->y1 = rand() % 100;
arr[i]->y2 = rand() % 100;
printf("Lungezza: %d\n", (int)length(arr[i]));
}
delete_longer(arr, SIZE, 80);
for(int i = 0; i < SIZE && arr[i]; i++)
{
printf("Lunghezza 2: %d\n", (int)length(arr[i]));
}
return 0;
}
First of all the free function should come after the instruction that sets the pointer to NULL, but that's not the main cause of the problem.
What causes the behaviour I described was the fact that the second for loop in the main stops after finding the first NULL pointer. Instead I should have written:
for(int i = 0; i < SIZE ; i++)
{
if(arr[i])
printf("Lunghezza 2: %d\n", (int)length(arr[i]));
}
You have two main problems:
In the delete function you write:
as[i] = NULL;
free(as[i]);
This is the wrong order. You must first free the memory and then set the element to null. But note that this is not the cause of your perceived problem, it only causes a memory leak (i.e. the memory of as[i] becomes inaccessible). You should write:
free(as[i]);
as[i] = NULL;
Your second problem is in your for loop, which now stops at the first null element. So not all the memory after it is deleted, you just don't print it. The loop should be for example:
for(int i = 0; i < SIZE; i++)
{
printf("Lunghezza 2: %d\n", arr[i]?(int)length(arr[i]):0);
}
Note: I agree with the discussion that free(NULL) may be implementation dependent in older implementations of the library function. In my personal opinion, never pass free a null pointer. I consider it bad practice.
There's no way to change the size of an array at runtime. The compiler assigns the memory statically, and even automatic arrays are fixed size (except if you use the last C standard, in which you can specify a different size at declaration time, but even in that case, the array size stands until the array gets out of scope). The reason is that, once allocated, the memory of an array gets surrounded of other declarations that, being fixed, make it difficult ot use the memory otherwise.
The other alternative is to allocate the array dynamically. You allocate a fixed number of cells, and store with the array, not only it's size, but also its capacity (the maximum amount of cell it is allow to grow) Think that erasing an element of an array requires moving all the elements behind to the front one place, and this is in general an expensive thing to do. If your array is filled with references to other objects, a common technique is to use NULL pointers on array cells that are unused, or to shift all the elements one place to the beginning.
Despite the technique you use, arrays are a very efficient way to access multiple objects of the same type, but they are difficult to shorten or enlengthen.
Finally, a common technique to handle arrays in a way you can consider them as variable length is to allocate a fixed amount of cells (initially) and if you need more memory to allocate double the space of the original (there are other approaches, like using a fibonacci sequence to grow the array) and use the size of the array and the actual capacity of it. Only in case your array is full, you call a function that will allocate a new array of larger size, adjust the capacity, copy the elements to the new copy, and deallocate the old array. This will work until you fill it again.
You don't post any code, so I shall do the same. If you have some issue with some precise code, don't hesitate to post it in your question, I'll try to provide you with a working solution.
I have a trouble regarding to multi-dimensional array in C.
We have to make a multi-dimensional array in which in which the user has to input the size of the array. After that according to the size C has to create a multi-dimensional array. Remember, in the center there always has to be '1'.
At every side of one there should be '2'. on every side of '2' there should be '3', depends upon the size of array. Also shown in image.
can locate the mid point of an array but when i do this: int Array[size/2][size/2] it gives me error. and how i can adjust other 2,3 and and other numbers at the sides?
This is the code I have written for now:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(){
const size;
printf("Enter the size: ");
scanf("%d", &size);
int Grid[size][size];
Grid[size/2][size/2] = 1;
printf("%d", Grid[1][1]);
return 0;
}
Firstly, you shall not do such a thing in C :
int grid[size][size];
If you're interested in knowing why, look at C11's Initialization paragraph :
No initializer shall attempt to provide a value for an object not contained within the entity being initialized.
The type of the entity to be initialized shall be an array of unknown size or a complete object type that is not a variable length array type.
Then, I'm not a fan of
const size;
Since the type is not explicit and your variable isn't const here. Even if you're using scanf, you do modify the value of size during the function.
But then, let's hit the problem ;)
I suggest you use a function to allocate your array. It will help clarifying your code :
int** create_array(int size)
{
int i;
int** array;
i = 0;
// You allocate the first dimension of your array
// (the one that will contain other arrays)
array = malloc(size * sizeof(int *));
if (array != NULL)
{
while (i < size)
{
// You allocate each 'sub-array' that will contain... ints !
array[i] = malloc(size * sizeof(int));
i += 1;
}
}
return (array);
}
Now this function returns a well-allocated array of the size you want. Don't forget to check if it's NULL in your calling function, and to free it (if it has been allocated).
To free the array, I'll let you write the function yourself, since it is very similar to the initialization. But still, be careful considering some sub-array might be NULL!
Then the initialization. The most simple way I can think of is iterating on your array and calculating the delta from the center.
int most_far;
////
/// Insert the loop stuff here...
//
if (x == size/2 && y == size/2)
array[x][y] = 1;
else
{
// You could use a ternary here but I don't know if you're familiar with them
// You're getting the position that is the most far from center...
if (abs(x - size/2) > abs(y - size/2))
most_far = abs(x - size/2);
else
most_far = abs(y - size/2);
// With this position, you calculate the 'distance' between the center and your position.
// This distance is your number ! :D
array[x][y] = most_far;
}
//
/// End of the loop, interations, etc...
////
Little tip : I suggest you do the population stuff in some function that returns a boolean. This boolean will be false if one sub-array has been found NULL during the population. And if it's the case, you probably don't want to read/display it !
Pfiouh, what a massive answer I wrote !
Hope it won't scare you (and that you'll find some help in it)
If your targeted element is in position a[2][2] then the condition will be some what like this.
Consider i to be row and j to be column.
if(a[i+1][j]==a[i+1][j+1]==a[i+1][j-1]==a[i][j+1]==a[i][j-1]==a[i-1][j]==a[i-1][j+1]==a[i-1][j-1])
flag=1; \\any process you want
and you can only assign constant to an array while declaring it. You can't assign a value like
int array[size/2][size/2];
There are two ways of doing this you might consider:
Filling entries in a growing square. (i.e., filling all the 1s, then the 2s, then the 3s, ...)
Figuring out a "formula" or procedure for each row.
Looking at the first method:
void fillSquare(int **arr, int n, int size)
{
fillSquareTopSide(arr, n, size);
fillSquareLeftSide(arr, n, size);
fillSquareRightSide(arr, n, size);
fillSquareBottomSide(arr, n, size);
}
where n is the current number (1, 2, or 3) and size is 3. And then a possible implementation of fillSquareTopSide:
void fillSquareTopSide(int **arr, int n, int size)
{
for(int i = size - n; i < size + n; i++)
arr[size - n][i] = n;
}
Below there is a unfinished code for my program, at the current stage, however, I am getting errors (Xcode log: Subscripted value is not array, pointer or vector). I suppose that it has to do with memory allocation. This error occurs in the if statement when I try to assign value of 1 to (*map[x2][y2]).exist and in map[x1][y1] = NULL;. Could you please show the proper way of assigning values to such variables.
Thank you in advance!
#include <stdio.h>
#include <stdlib.h>
typedef struct{
int num;
_Bool exist;
}name;
int main(void){
name* map[10][10];
name* guy;
guy = (name*)malloc(10*sizeof(name));
int x1, y1, x2, y2;
int m, n, o;
for(m = 0; m < 10; m++){
for(n = 0; n < 10; n++){
map[m][n] = NULL;
}
}
for(o = 0; o < 10; o++){
(*(guy+o)).num = rand() % 4;
(*(guy+o)).exist = 1;
do{
m = rand() % 10;
n = rand() % 10;
}while (map[m][n] != NULL);
map[m][n] = guy + o;
}
if(map[x2][y2] == NULL){
name *map = malloc(10*10*sizeof(name));
(*map[x2][y2]).exist = 1;
map[x1][y1] = NULL;
}
return 0;
}
Besides the x2 and y2 not having a defined value - they do not default to 0, and the map variable in your if statement hiding the map outside your if statement, you seem to be having problems with understanding how to allocate memory as well as accessing it after it is allocated.
I suggest fixing the guy variable first and then using that experience to apply to the map variable.
The guy variable as you have it written, points to a block of memory that can hold 10 name structures. That doesn't mean that there are 10 name structures there, it just means it is a block of memory large enough to hold 10 name structures. Note that the block is not sized to hold 10 pointers to name structures but 10 actual name structures.
When you do arithmetic on the guy variable like (guy+o) you are not moving o name structures into the memory block since guy is of size pointer to name, not size of name. If pointers on your system are 4-bytes in size and the name structure is maybe 8-bytes in size then you are not moving the correct number of bytes into the block, so you are not pointed at the right place.
If you want to initialize the 10 names in guy then do yourself a favor until you are really good with pointers - create the guy variable as an array of name pointers.
So the guy definition becomes
name* guy[10];
and the initialization of 10 names in guy becomes
for ( m = 0; m < 10; m++ ) {
guy[m] = malloc( sizeof( name ) );
if ( guy[m] ) {
guy[m]->num = rand() % 4;
guy[m]->exist = 1;
}
}
instead of
guy = (name*)malloc(10*sizeof(name));
Since guy will now be recognized as a pointer to an array of name pointers, when you do arithmetic like (guy + o) it will use a pointer to a different name structure. But I would avoid that to make your life easier. Just use guy[o] to access the pointer at that location in the guy array.
You should be able to apply the same rules to map to make your code work.
I can post the whole code if you guys want, but here is the essence of my problem:
typedef struct
{
CardT cards[DECK_SIZE];
int count;
}DeckT;
void shuffleDeck(DeckT *deck){
int k=50;
DeckT *randCard = deck;
DeckT *startCard = deck;
while (k>0){
int r = k % 25;
int i = 0;
for(i=0; i < r; i++, randCard++){
printf("%i %i",i,r);
}
CardT A; //do I declare A to be a Card Struc or a pointer to the array of cards?
A = *randCard; //this is where my program locks up.
*randCard = *startCard; //swapping pointers seems pointless [hehe]
*startCard = A;
printf(" yo yo yo shuffle\n"); //doesn't print this line at all, locks up before
k--;
*startCard++;
}
I understand that I need to swap the actual elements and not the pointers, but I am unsure how to do it. Basic flow of the function is to declar two pointers to my deck, which point to the array of cards [ do i need to specify this?] then swap cards based on the k%25.
I'm not to worried about the actual randomness of the swapping right now, i just want to know how to swap two cards[which are themselves structs].
Your
DeckT *startCard
should be
CardT *startCard = &deck->cards[0];
Ditto for randCard but this variable can/should be moved in the inner loop
You got confused about which pointers to use. Deck* points to a deck structure. If you add 1 to it, it will point to a Deck immediately following the first one (as if you had an array of decks). I'm pretty sure you didn't mean that.
You want to operate on CardT. There's no need to use the pointers. If you have two indices to swap, let's say i and j, just operate directly on the cards array:
CardT temp = deck->cards[i];
deck->cards[i] = deck->cards[j];
deck->cards[j] = temp;
I'm attempting to create a simple 2D array in C but apparently running into some memory trouble. My setup is simple enough and I can't tell what's wrong. I admit that my understanding of pointers is insufficient, but I still think this should be working. Can anyone see the flaw here?
typedef unsigned int DATUM;
DATUM **series_of_data;
void initialize_data()
{
*series_of_data = (DATUM *) malloc(1024 * sizeof(DATUM));
}
This causes my program to crash with a bus error when I run it.
series_of_data is actually not allocated.
You have various way to allocates a 2D array, either using the array of rows model whcih has bad cache coherency and thus has usually bad performances or to use the Iliffe vector adviced in Numerical recipes in C that consists in allocating one huge h*w memory block and a side pointer array which contains the beginning of your rows (or columns) :
DATUM** alloc_array( int h, int w )
{
int i;
DATUM** m = (DATUM**)malloc(h*sizeof(DATUM*));
m[0] = (DATUM*)malloc(h*w*sizeof(DATUM));
for(i=1;i<h;i++) m[i] = m[i-1]+w;
return m;
}
void release_array(DATUM** m)
{
free( m[0] );
free( m);
}
int main()
{
int r,c;
DATUM** tab;
int width = 5;
int height = 3;
tab = alloc_array(height, width); /* column first */
for(r = 0;r<height;++r)
for(c = 0;c<width;++c)
tab[r][c] = (1+r+c);
for(r = 0;r<height;++r)
{
for(c = 0;c<width;++c)
{
printf("%d\t",tab[r][c]);
}
puts("");
}
release_array(tab);
}
Data are nicely packed in memory, so cache are happy and you keep the [][] access pattern.
As a matter of speed this is in +/-3% speed of the classical DATUM* + polynomial access method.
series_of_data is an invalid pointer - you don't assign it to anything. When you try to assign to its memory location (*series_of_data = ...), it's putting stuff in a random place, which is likely to not do what you want. You have to point series_of_data somewhere useful, e.g.
series_of_data = (DATUM **)malloc(16 * sizeof(DATUM *))
for an array with 16 slots for DATUM * pointers in it.
You haven't allocated the series_of_data pointer before you assign to *series_of_data.
For example, if series_of_data is intended to be an array then you would need to write something like this:
series_of_data = malloc(n*sizeof(DATUM*));
where n is the length of the series_of_data array.
Only after you have done this can you assign to *series_of_data.