Having problems with a cellular automation in C - c

Now having corrected all of the errors thrown up by GCC, the output is different than before, but still only changes once.
OUTPUT:
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 1 1 0
0 0 0 0 0 0 0 0 0 1
It stays like this for 40 passes, which it shouldn't
THE NEW (WARNING FREE) CODE:
signed char board [10][10]; //the board
int evaluate_cell (int i, int a);
int evaltheboard(void){
//loops through the array, and stops to check if there is a living cell. leiving cells are represented by a 1.
int i,a;
signed char cell_to_check [1][1];
for (a=0;a<=9;a++){
for (i=0;i<=9;i++){
cell_to_check[0][0] = board[i][a];
if (cell_to_check[0][0] != 0){
evaluate_cell(i,a);
}
}
}
return 0;
}
int evaluate_cell(int i,int a){
// checks near by cells to see if there are any living and chooses whether the cell should live based off of it's living neighbors.
signed char live_n_cells = 0, empty_x_mod, empty_y_mod;
signed char x_inc [8] = {0,1,1,1,0,-1,-1,-1}, y_inc [8]={-1,-1,0,1,1,1,0,-1};
int z, x, y;
x=y=0;
//printf("evaling cell\n");
//printf ("co-ords being checked [%d][%d]", i,a);
for (z=0;z<=7;z++){
if (board[(i+(x_inc[x]))][(a+(y_inc[y]))] != 0){
++live_n_cells;
}
else if(board[(i+(x_inc[x]))][(a+(y_inc[y]))] == 0){
empty_x_mod = i-(x_inc[x]) ;
empty_y_mod = a-(y_inc[y]);
}
y++;
x++;
}
//printf("%d = z, %d = y, %d = x\n", z, y, x);//debug
//printf("|close living cells = %d\n", live_n_cells); // debug
//printf("|empty mods are %d %d\n", empty_x_mod, empty_y_mod); //debug
if (live_n_cells >= 3){
board[i][a] = 0;
}
else if (live_n_cells == 0){
board[i][a] = 0;
}
else if (live_n_cells == 1 || 2){
board[empty_x_mod][empty_y_mod] = 1;
}
return 0;
}
int print_array(void){
//prints array
int i,a;
for (a=0;a<=9;a++){
for (i=0;i<=9;i++){
printf(" %d", board[i][a]);
//printf("%d", i);
}
printf("\n");
}
printf("----------\n");
return 0;
}
int main(void){
int x;
//runs the damned thing
board[5][5] = 1; //DEBUG
board[5][6] = 1; //DEBUG
board[6][5] = 1; //DEBUG
for (x=0;x<40;x++){
evaltheboard();
print_array();
}
return 0;
}
OLD QUESTION:
Like the title says, i am having some unexpectedly stagnant output. The program should function like Conway's Game of Life. When i run this version, it changes the 'board' array once and doesn't seem to do it again. the out put ends up looking like this (0 = empty cell, 1 = living cell):
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 1 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 0
So in theory, the two adjacent ones should have re-populated and the isolated ones should have died off, but they didn't. Any help into why this would be would be met with thanks.
Please don't be too harsh, this is my first actually project in c that I have written from the ground up. Any feed back on my general form of code would be appericieated
THE CODE:
signed char board [10][10]; //the board
int evaltheboard(void){
//loops through the array, and stops to check if there is a living cell. living cells are represented by a 1.
int i,a;
signed char cell_to_check [1][1] = {0};
for (a=0;a<=9;a++){
for (i=0;i<=9;i++){
cell_to_check[0][0] = board[i][a];
if (cell_to_check[0][0] != 0){
evaluate_cell(i,a);
}
}
}
return 0;
}
int evaluate_cell(int i,int a){
// checks near by cells to see if there are any living and chooses whether the cell should live based off of it's living neighbors.
signed char live_n_cells = 0, empty_x_mod, empty_y_mod;
signed char x_inc [8] = {0,1,1,1,0,-1,-1,-1}, y_inc [8]={-1,-1,0,1,1,1,0,-1};
int z, x, y;
x=y=0;
//printf("evaling cell\n");
//printf ("co-ords being checked [%d][%d]", i,a);
for (z=0;z<=7;z++){
if (board[(i+(x_inc[x]))][(a+(y_inc[y]))] != 0){
++live_n_cells;
}
else(board[(i+(x_inc[x]))][(a+(y_inc[y]))] == 0);{
empty_x_mod = i-(x_inc[x]) ;
empty_y_mod = a-(y_inc[y]);
y++;
x++;
}
}
//printf("%d = z, %d = y, %d = x\n", z, y, x);//debug
//printf("|close living cells = %d\n", live_n_cells); // debug
//printf("|empty mods are %d %d\n", empty_x_mod, empty_y_mod); //debug
if (live_n_cells >= 3){
board[i][a] = 0;
}
else if (live_n_cells = 0){
board[i][a] = 0;
}
else(live_n_cells = 1 || 2);{
board[empty_x_mod][empty_y_mod] = 1;
}
return 0;
}
int print_array(void){
//prints array
int i,a;
for (a=0;a<=9;a++){
for (i=0;i<=9;i++){
printf(" %d", board[i][a]);
//printf("%d", i);
}
printf("\n");
}
printf("----------\n");
return 0;
}
int main(void){
int x;
//runs the damned thing
board[5][5] = 1; //DEBUG
board[5][6] = 1; //DEBUG
board[6][5] = 1; //DEBUG
for (x=0;x<40;x++){
evaltheboard();
print_array();
}
return 0;
}
note: the printf's with //'s in front of them are for debugging only, and the forloop in main is only temporary. i plan to do a while that checks if any thing is still alive later. if it says //DEBUG afterwards, it is also temporary.
anyway, Thanks!

There are a few things you need to look at in your code. The best thing you could do is enable compiler warnings, if you are using gcc add the -Wall (warn all) flag to the compile line, so to compile use:
gcc -Wall source.c -o Program
Most compilers support some sort of warning flag/option. When I compiled your code with this flag I got the following output (trimmed a bit):
7:5: warning: missing braces around initializer [-Wmissing-braces]
signed char cell_to_check [1][1] = {0};
31:13: warning: statement with no effect [-Wunused-value]
else(board[(i+(x_inc[x]))][(a+(y_inc[y]))] == 0);{
44:5: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
else if (live_n_cells = 0){
12:17: warning: implicit declaration of function ‘evaluate_cell’ [-Wimplicit-function-declaration]
evaluate_cell(i,a);
When I went through and fixed these issues, the compiler provided more issues, but eventually you should have a nice warning free program (suggesting that your code might be correct).
The first warning above is because you are trying to assign an array with one element to a variable which expects an array of and array with one element.
The second warning above is because you are missing an if after your else, so this should be else if (...), however something else you should note is that you have a ; before the curly brackets, this probably shouldn't be there at all, you should go through your code an make sure you don't have extra ;s before curlly brackets.
The third warning is probably because you are making an assignment live_n_cells = 0 instead of checking live_n_cells == 0. If you actually meant to make the assignment, then write (live_n_cells = 0). A good way to avoid every accidently making assignments is to use 0 == live_n_cells, this way if you forget the second equals sign you never make an assignment.
The fourth warning is about a missing declaration of your function. to resolve this, you can add something like int evaluate_cell(int i,int a); to the top of your source file.
Try these things and then post an update to your question (these tips may even help to solve your problem).
EDIT:
A few more tips:
Functions can be declared as void, which means that they don't return a value. This could be useful in your program since evaluate_cell currently returns 0, which you simply ignore. You could instead write void evaluate_cell(int i, int j), but remember to change the declaration at the top of your source file too.
I went over your reproduction code, it doesn't seem to contain all the Game of Life operations (at least according to the Wikipedia page http://en.wikipedia.org/wiki/Conway's_Game_of_Life), try the following:
if (live_n_cells == 3 && board[i][a] == 0) { // production
temp_board[i][a] = 1;
} else if (live_n_cells > 3) { // over population
temp_board[i][a] = 0;
} else if (live_n_cells < 2) { // under population
temp_board[i][a] = 0;
} else { // reproduction
temp_board[i][a] = board[i][a];
}
And also call your evaluate cell routine for all cells, not just the currently alive cells. You also probably notice the use of the variable temp_board in the above code. This is related to the comment posted by aschepler on your question. I also changed the definition of the board to the following, the +2 is padding to make sure you never try to access elements outside the array.
#define WIDTH 10
#define HEIGHT 10
signed char board [HEIGHT+2][WIDTH+2]; ///< the board
signed char temp_board [HEIGHT+2][WIDTH+2]; ///< temporary board
Finally, I changed the code in evaluateboard to:
int i, j; ///< loop counters
// Evaluate each cell in array
for (j=1; j<=HEIGHT; j++) {
for (i=1; i<=WIDTH; i++) {
evaluate_cell(j,i);
}
}
// copy temp_board into board
for (j=1; j<=HEIGHT; ++j) {
for (i=1; i<=WIDTH; ++i) {
board[j][i] = temp_board[j][i];
}
}
Using most of your code, with the above few tweaks, I managed to get Conway's Game of Life running with the expected results.
One final tip, it is usually the convention in C/C++ to use i, j, k, l, m, n (often in that order) as your loop counting variables.
Good luck. :)

There are some bugs in evaluate_cell.
First, when you check around a cell on the border, you access areas outside the board. You need to check if a surrounding cell is outside the board!
Second, you use assignment instead of comparison in your if statements.
You probably mean:
else if (live_n_cells == 0){ // = is assignment, == is equality
The else should probably be:
else { // Only way to get here is if live_n_cells is 1 or 2, so no need for a condition.

Related

I cannot understand core dump cause of fgetc, how can I fix it?

I allocated matrix like this :
prevMatrix = (int**)malloc(sizeof(int) * arraySize[0]);
for (int i = 0; i < arraySize[0]; i++) {
prevMatrix[i] = (int*)malloc(sizeof(int) * arraySize[1]);
}
I checked arraySize[] has normal value. arraySize[0] means row, and arraySize[1] means column.
and I handed over the matrix like this :
void getInputMatrix(FILE* input, int column, int** matrix)
getInputMatrix(input, arraySize[1], prevMatrix);
and then function's body is this :
void getInputMatrix(FILE* input, int column, int** matrix) {
int i = 0, j = 0, c = 0;
while (!feof(input)) {
if (j == column) {
j = 0;
i++;
}
c = fgetc(input);
if (c != EOF && c != 32 && c != 10 && c != 13) {
matrix[i][j] = c - 48;
j++;
}
}
}
this is the example of matrix file:
1 0 0 0 0 0 0
0 1 0 1 0 0 0
0 1 0 0 1 1 0
0 1 1 1 0 0 0
0 0 0 0 1 0 0
0 1 0 0 0 1 0
1 0 1 1 0 0 0
0 1 0 0 0 0 1
It works very well in VS 2019, but it cause segmentation fault in Linux system(Ubuntu).
This program works well in Linux till the column is 6 or 7, but it occurs corrupted size vs. prev_size error or segmentation faultwhen the column overs that number.
Is it a problem of allocation? or fgetc()?
How can I fix it?
For starters, your first level allocation should be using the size of an int pointer rather than an int:
int **prevMatrix = malloc(sizeof(int*) * arraySize[0]);
If those types are different sizes, your original code could have a problem.
And, just as an aside, you should not cast the malloc return value in C, it can cause subtle problems.

Updating a matrix with special cases

I am trying to write a function which gets a matrix 9x9 and updates it accordingly to user's input with the following rules:
Valid number is between 1 and 9 (zero is invalid).
I have to use scanf until I get EOF.
Input has digits and symbols. valid input is a pair of two digits following with a symbol or EOF or space. string with more than two digits is invalid. for example (123% isn't valid but 12% is valid).
Example:
Input: 10 33%55^21 $123%
Output:
0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
Explanation: 10 and 123 are invalid. 33, 55 and 21 are valid so we will put 1 in 22, 44 and 10.
What I tried to do:
void updateMarix(int matrix[][9]) {
int digits = 0, one_previous, two_previous;
char input;
while (scanf("%c", &input) != EOF) {
if(isValidDigit(input)) {
digits++;
if(digits == 1) {
two_previous = input - '0' - 1;
continue;
} else if(digits == 2){
one_previous = input - '0' -1;
continue;
}
} else if(digits == 2) {
matrix[two_previous][one_previous]++;
}
digits = 0; // reset
}
}
most tests are end with success, but some of them are fail. I think that is because I don't handle with the last input (if for example it ends with 22 it won't update it because with my implementation, the update is in the next iteration when other symbol got as input).
Is there a better implementation for this? My code became messy and not clean.
*Edit: It should ignore invalid input and a3b doesn't counts, a03b also doesn't counts but a13b does counts as 13 meaning we should increase the number in matrix[0][2].
Edit 2: #JonathanLeffler menationed FSM so I tried to create one:
Although it doesn't handles the case of 1234 (invalid number) or 123 (also invalid). The most similar thing was to create an arrow from second number to symbol (but it isn't quite true because in 1234%12 only 12 is valid.
I think your FSM needs 4 states plus the end state:
Zero digits read (D0).
One digit read (D1).
Two digits read (D2).
Digits are invalid but no more error reporting needed (DI).
There are 4 different inputs, too:
Digit 1-9.
Digit 0.
Other.
EOF.
I've used a switch on state and if/else code in each state, but it leads to somewhat verbose code. OTOH, I believe it handles inputs correctly.
/*
** FSM
** States: 0 digits (D0), 1 digit (D1), 2 digits (D2), digits invalid (DI)
** Inputs: digit 1-9 (D), digit 0 (0), other (O), EOF.
** Action: S - save, E - error, I - ignore, P - print
** Body of FSM encodes "action;state"
**
** State D0 D1 D2 DI
** Input
** D S;D1 S;D2 E;D2 I;DI
** O I;D0 E;D0 P;D0 I;D0
** 0 E;D2 E;D2 E;D2 I;DI
** EOF I;end E;end P;end I;end
*/
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
enum State { D0, D1, D2, DI };
enum Input { Digit, Zero, Other, End };
static int debug = 0;
static enum Input input(int *rv)
{
int c = getchar();
if (debug)
printf("Input: %c\n", (c == EOF) ? 'X' : c);
*rv = c;
if (c == EOF)
return End;
if (isdigit(c))
{
*rv = c - '0';
return (c == '0') ? Zero : Digit;
}
return Other;
}
static void updateMatrix(int matrix[9][9])
{
char pair[2] = { 0, 0 };
enum State state = D0;
int c;
enum Input value;
while ((value = input(&c)) != End)
{
switch (state)
{
case D0:
if (value == Digit)
{
pair[0] = c;
state = D1;
}
else if (value == Zero)
{
fprintf(stderr, "Received zero digit - invalid\n");
state = DI;
}
else
{
assert(value == Other);
}
break;
case D1:
if (value == Digit)
{
pair[1] = c;
state = D2;
}
else if (value == Zero)
{
fprintf(stderr, "Received zero digit - invalid\n");
state = DI;
}
else
{
assert(value == Other);
fprintf(stderr, "Received one digit where two expected\n");
state = D0;
}
break;
case D2:
if (value == Digit)
{
fprintf(stderr, "Received more than two digits where two were expected\n");
state = DI;
}
else if (value == Zero)
{
fprintf(stderr, "Received zero digit - invalid\n");
state = DI;
}
else
{
assert(value == Other);
printf("Valid number %d%d\n", pair[0], pair[1]);
matrix[pair[0]-1][pair[1]-1] = 1;
state = D0;
}
break;
case DI:
if (value == Other)
state = D0;
break;
}
}
if (state == D2)
{
printf("Valid number %d%d\n", pair[0], pair[1]);
matrix[pair[0]-1][pair[1]-1] = 1;
}
else if (state == D1)
fprintf(stderr, "Received one digit where two expected\n");
}
static void dump_matrix(const char *tag, int matrix[9][9])
{
printf("%s:\n", tag);
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
printf("%4d", matrix[i][j]);
putchar('\n');
}
}
int main(void)
{
int matrix[9][9] = { 0 };
updateMatrix(matrix);
dump_matrix("After input", matrix);
return 0;
}
On your test input, it produces the output:
Received zero digit - invalid
Valid number 33
Valid number 55
Valid number 21
Received more than two digits where two were expected
After input:
0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
On the mostly-invalid input file:
123345132
bbbb12cccc1dddd011dd
it produces the output:
Received more than two digits where two were expected
Valid number 12
Received one digit where two expected
Received zero digit - invalid
After input:
0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
You can argue (easily) that the error messages could be more informative (identifying the erroneous character, and possibly the prior valid digits), but it only produces one error message for each invalid sequence, which is beneficial.
You could use a combination of fgets(), sscanf() and strpbrk() for this.
The input line is read into a character array str and a pointer ptr pointing to the part of the string in str being processed is maintained.
First, set up a loop to read input line by line. fgets() will return NULL on EOF.
for(; fgets(str, sizeof(str), stdin); )
{
...
...
...
}
fgets() will read in the trailing newline as well. You could remove it like
str[strlen(str)-1]='\0';
Now inside the above loop, use another loop to process the input line in str like
for(ptr=str; (ptr=strpbrk(ptr, "0123456789"))!=NULL; ptr+=len)
{
sscanf(ptr, "%d%n", &n, &len);
if(n>10 && n<100)
{
//accepted
printf("\n%d", n);
arr[n/10][n%10]=1;
}
//else discarded
}
strpbrk()'s prototype is
char *strpbrk(const char *s1, const char *s2);
and it returns a pointer to the first character in s1 which is a character in the string s2. If there is no match, NULL is returned.
So we are looking to see the first digit part in str that remains to be processed with strpbrk(ptr, "0123456789").
This number part is read into n via sscanf(). If this number is in the range you need, you may accept it.
The %n format specifier is used to find out the number of characters which has been scanned with the sscanf() inorder to find the value by which ptr must be updated. See this post.
The digit in the ones place will be n%10 and that in the tens place will be n/10 as the number you need is a 2-digit number.
You may set your array representing the matrix like
arr[n/10][n%10]=1;
So the whole thing could look something like
char *ptr, str[50];
for(; fgets(str, sizeof(str), stdin); )
{
for(ptr=str, str[strlen(str)-1]=0; (ptr=strpbrk(ptr, "0123456789"))!=NULL; ptr+=len)
{
sscanf(ptr, "%d%n", &n, &len);
if(n>10 && n<100)
{
printf("\n%d", n);
arr[n/10][n%10]=1;
}
}
}
And for your input 10 33%55^21 $123%, the output would be
33
55
21
as 10 and 123 will be discarded.

Dynamic 2D array elements are not accessible several for loop

I've studied data structure and algorithm, and I got a problem with dynamic 2d array. Here is part of my code. The coding problem is the Knight's tour.
int iMove[8] = {-2, -1, 1, 2, 2, 1, -1, -2};
int jMove[8] = { 1, 2, 2, 1,-1, -2, -2, -1};
cell* cellList(int* i, int* j, int** board){
int k;
cell* temp;
int iTempNext; int jTempNext;
int maxSampleNum = 8;
int cnt = 0;
int val;
for(k = 0; k < maxSampleNum; k++){
iTempNext = (*i) + iMove[k];
jTempNext = (*j) + jMove[k];
//1. get list 0<=i<=7 && 0<=j<=7
if( (0 <= iTempNext && iTempNext <= 7) && (0 <= jTempNext && jTempNext <= 7)){
//2. get the 0 value cells
//val = canMove(iTempNext, jTempNext, board);
printf("%d %d\n", iTempNext, jTempNext);
if(board[iTempNext][jTempNext] == 0){
cell tempCell;
tempCell.row = iTempNext;
tempCell.col = jTempNext;
temp = (cell*)realloc(temp, sizeof(cell));
*(temp+cnt) = tempCell;
cnt++;
}
}
}
return temp;
}
int** board : 2d array and I allocated it dynamically and initialized all elements of this array to 0. I printed 2d array after initializing.
The problem is that after 2nd for loop, this program got segmentation fault on accessing 2d array. I cannot access 2d array elements during 3rd for loop.
Initializing Complete...
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
Enter the start position (i, j): 3 3
iTempNext jTempNext
1 4
2 5
4 5
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400b1c in cellList (i=0x7fffffffe5bc, j=0x7fffffffe5c0, board=0x603010) at main.c:144
144 if(board[iTempNext][jTempNext] == 0){
this is the result after using gdb. How can I solve this problem
This line:
temp = (cell*)realloc(temp, sizeof(cell));
invokes undefined behaviour since temp is not initialized. You should initialize it with, e.g., cell *temp = NULL; (understand that realloc can either take a NULL pointer in which case it is equivalent to malloc, or a previously malloced/calloced/realloced pointer).
And don't cast the return from malloc. This is C, not C++. Search this site for why casting the malloc return value is frowned upon in C.

Setting 2D Integer Array values all to 0 in C

I am trying to set all the values in my 2D array to 0 and then print all the scores back to make sure they are correct.
struct Game {
int GameScoresHome[10][10];
};
int main() {
struct Game game;
memset(game.GameScoresHome, 0, sizeof game.GameScoresHome);
for (int x=0;x<100;x++) {
int y = floor(x/10);
printf("%d ",game.GameScoresHome[x][y]);
}
return 0;
}
The current output is:
0 0 0 0 0 0 0 0 0 0 0 0 822083893 32767 32767 32767 32767 32767 32767 1651067951 1634028652 1345283180 1702057263 1701080931 2054842477 1866870631 1885417061 1647262318 1146113364 896624241 1280918623 1919052108 1819042146 1818850626 1634956149 1852133983 1264923239 792545364 1666723698 1836345960 1163089152 1949263220 1919250021 1868774725 1213481296 796026224 1785230711 1650803759 792546380 1213481296 1868781615 1752003690 6780258 1497628720 778396783 1920232291 792545364 1666723698 1836345960 1735746149 796026224 1785230711 1650803759 0 0 3 0 7 0 -2147482624 0 0 0 0 0 0 0 0 0 0 233472 1869045599 48 1868783455 5312 1633967967 3480 1818320735 304 1919115103 0 1852796269 0 115 0 72 0 1227 0 0
The first 11 zeros are as they should be then it all goes wrong. What's going on?
You're accessing memory outside the array.
Your x variable iterates from 0 to 99.
for (int x=0;x<100;x++)
But your array has only 10 rows.
int GameScoresHome[10][10];
One fix would be to use simple nested loops.
for (int x=0;x<10;x++) {
for (int y=0;y<10;y++) {
printf("%d ",game.GameScoresHome[x][y]);
}
}
Nested loops would also make it easy to include a newline after each row.
for (int x=0;x<10;x++) {
for (int y=0;y<10;y++) {
printf("%d ",game.GameScoresHome[x][y]);
}
printf("\n");
}
In your code
for (int x=0;x<100;x++) {
int y = floor(x/10);
printf("%d ",game.GameScoresHome[x][y]);
}
the x value is going out of bound. Maybe you want to take a %10 value of x and change the index locations, like
printf("%d ",game.GameScoresHome[y][x%10]);
or, use a nested loop to maintain two indexes separately.
What about?
struct Game game = {.GameScoresHome = {0}};
for (int x=0;x<10;x++) {
for (int y=0;y<10;y++) {
printf("%d ",game.GameScoresHome[x][y]);
}
printf("\n");
}
Write the loop simpler
for ( int x = 0; x < 100; x++) {
printf("%d ",game.GameScoresHome[x / 10][x % 10]);
}
or
for ( int x = 0; x < 100; x++) {
printf("%d ",game.GameScoresHome[x / 10][x % 10]);
if ( x % 10 == 9 ) printf( "\n" );
}
As for your loop then x is being changed from 0 up to 100 and as result using x as the first index in the statement
printf("%d ",game.GameScoresHome[x][y]);
^^^
is invalid. And y is calculated incorrectly.

Pthreads update on global 2D array segfaults on execution

Hi all and thanks for your time.
I am trying to parallelise a program which executes some commands and I thought pthreads would be a good option.
But I am running into some issues.
This is where I start the threads:
void timetravel(command_stream_t s)
{
int *retvals[MAXTHREADS];
if (s == NULL)
return;
if (s->num_commands == 0)
return;
int err;
global_table = create_dependency_table(s);
//global_command = &s;
global_command = s;
int fill = 0;
for (fill = 0; fill < s->num_commands; fill++)
{
global_table.status_table[fill] = 1; //Set all commands to waiting
// printf("global_table.status_table[i] : %d \n", global_table.status_table[fill]);
}
int finished = 0;
while (finished == 0)
{
finished++;
int threadindex = 0;
for (threadindex = 0; threadindex < MAXTHREADS; threadindex++)
{
err = pthread_create(&(tid[threadindex]), NULL, &parallelexecute, NULL);
if (err != 0)
printf("\ncan't create thread :[%s]", strerror(err));
else
printf("\n Thread created successfully\n");
}
for (threadindex = 0; threadindex < MAXTHREADS; threadindex++)
{
pthread_join(tid[threadindex], NULL);
}
if (completecheck(global_table) == 0)
{
finished = 1;
}
}
// print_dependency_table(global_table);
//print_command(global_command->command_array[1]);
}
The dependency table is stored as such
*** DEPENDENCY TABLE ***
~x~ ~meh~ ~hello~ ~goodbye~ ~phi~ ~a~ ~gamma~ ~delta~ ~b~ ~c~ ~d~ ~e~ ~f~ ~g~
1 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0
0 0 1 1 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 1 1 1 1 1
for the commands
cat x meh
echo hello
echo -s hello goodbye > phi
touch a < gamma > delta
touch -rx b c d e f g
As "hello" is used in command 2 and 3, 3 is dependent on 2 and so we have
~x~ ~meh~ ~hello~ ~goodbye~ ~phi~ ~a~ ~gamma~ ~delta~ ~b~ ~c~ ~d~ ~e~ ~f~ ~g~
0 0 1 0 0 0 0 0 0 0 0 0 0 0
0 0 1 1 1 0 0 0 0 0 0 0 0 0
So we will not run 3 before 2
After 2 is run, we set its row to 0, so 3 is no longer dependent on it
I have not implemented blocking of any kind because there are no Write/Write conflicts.
We might have a race condition where there is a read before a write, but that is fine - as it only delays thread execution which is ok.
This is the pthreads program:
void* parallelexecute(void *arg)
{
//printf("gets to parallel execute stage\n");
int i;
//printf("global_table.num_cmds_rows : %d \n",global_table.num_cmds_rows);
for (i = 0; i < global_table.num_cmds_rows; i++)
{
// status 1 = runnable, status 2 = running
//status 0 = completed successfully, status -1 = unsuccessful
//printf("global_table.status_table[i] : %d \n",global_table.status_table[i]);
if (global_table.status_table[i] == 1
&& (check_nth_command(&global_table, i)) == 0)
{
global_table.status_table[i] = 2;
execute_command(global_command->command_array[i], 0);
printf("execution triggered");
completed_nth_command(&global_table, i, 0);
break;
}
}
return NULL;
}
These are my global variables
#define MAXTHREADS 2
pthread_t tid[MAXTHREADS];
//global variable for dependency pool
parallel_data global_table;
//global variable for commands
command_stream_t global_command;
But I notice when I try to access global_table from parallelexecute I get all sorts of odd values and I am not sure why.
'global table' is a struct thus:
struct parallel_data
{
int** dependency_table; // the main dependency table
char** file_reference_key; // find index by name (use strcmp in a loop)
int* status_table; // you know you are done when all the statuses are 0 (none should ever be -1)
int num_files_cols; // number of columns/files
int num_cmds_rows; // number of rows/commands
};
And each thread WRITES only on its row in dependency table, and its row in status_table
I am not quite sure how to proceed.
I am also reasonably certain of the supporting functions correctness.
Any help would be appreciated.
I haven't read your code yet, but I saw "I have not implemented blocking of any kind because there are no Write/Write conflicts", That's a MAJOR red flag to me. If you have Read/Write conflicts, then... well... you have conflicts. That's probably related to the bug. The only time it's valid is if you have std::atomic variables or volatile variables, and a quick CTRL+F says you have neither. Your code is probably not synchronizing at all, and thus threads are never seeing the values that the other threads are writing.
I figured out that my style of passing arguments to the pthreads thread function was incorrect - I shall post the edits I made to the code shortly.
Thank you #mooing-duck , #wilx

Resources