I'm working on a class assignment and I've run into an issue I haven't been able to figure out. I'm implementing the Ford-Fulkerson algorithm using BFS to find max flow. But while trying to set my Residual Capacity matrix to the given capacity, I hit a segmentation fault. In the test code we received, I can see that the original capacity matrix was passed by value by its address, but I have a feeling that in my code I'm not interacting with it the way I think I am? Which leads me to believe that I may have the same issue recurring elsewhere. I worked with gdb and saw that I hit a segmentation fault on this line here in my nested for loop :
resCap[i][j] = *(capacity + i*n + j);
However, nothing I have tried has worked for me though so I am pretty stumped.
void maximum_flow(int n, int s, int t, int *capacity, int *flow)
{
int i, j, resCap[n][n], path[n]; // residual capacity and BFS augmenting path
int min_path = INT_MAX; // min of the augmenting path
// Assign residual capacity equal to the given capacity
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
{
resCap[i][j] = *(capacity + i*n + j);
*(flow + i*n + j) = 0; // no initial flow
}
// Augment path with BFS from source to sink
while (bfs(n, s, t, &(resCap[0][0]), path))
{
// find min of the augmenting path
for (j = t; j != s; j = path[j])
{
i = path[j];
min_path = min(min_path, resCap[i][j]);
}
// update residual capacities and flows on both directions
for (j = t; j != s; j = path[j])
{
i = path[j];
if(*(capacity + i*n + j) > 0)
*(flow + i*n + j) += min_flow_path;
else
*(flow + j*n + i) -= min_flow_path;
resCap[i][j] -= min_flow_path;
resCap[j][i] += min_flow_path;
}
}
}
And here is the test code provided to us in case it is needed:
int main(void)
{ int cap[1000][1000], flow[1000][1000];
int i,j, flowsum;
for(i=0; i< 1000; i++)
for( j =0; j< 1000; j++ )
cap[i][j] = 0;
for(i=0; i<499; i++)
for( j=i+1; j<500; j++)
cap[i][j] = 2;
for(i=1; i<500; i++)
cap[i][500 + (i/2)] =4;
for(i=500; i < 750; i++ )
{ cap[i][i-250]=3;
cap[i][750] = 1;
cap[i][751] = 1;
cap[i][752] = 5;
}
cap[751][753] = 5;
cap[752][753] = 5;
cap[753][750] = 20;
for( i=754; i< 999; i++)
{ cap[753][i]=1;
cap[i][500]=3;
cap[i][498]=5;
cap[i][1] = 100;
}
cap[900][999] = 1;
cap[910][999] = 1;
cap[920][999] = 1;
cap[930][999] = 1;
cap[940][999] = 1;
cap[950][999] = 1;
cap[960][999] = 1;
cap[970][999] = 1;
cap[980][999] = 1;
cap[990][999] = 1;
printf("prepared capacity matrix, now executing maxflow code\n");
maximum_flow(1000,0,999,&(cap[0][0]),&(flow[0][0]));
for(i=0; i<=999; i++)
for(j=0; j<=999; j++)
{ if( flow[i][j] > cap[i][j] )
{ printf("Capacity violated\n"); exit(0);}
}
flowsum = 0;
for(i=0; i<=999; i++)
flowsum += flow[0][i];
printf("Outflow of 0 is %d, should be 10\n", flowsum);
flowsum = 0;
for(i=0; i<=999; i++)
flowsum += flow[i][999];
printf("Inflow of 999 is %d, should be 10\n", flowsum);
printf("End Test\n");
}
This line is likely going to segfault, it does using Clang.
int i, j, resCap[n][n], path[n];
You're declaring a very large array on the stack. Just how big can be seen when you try and allocated it using calloc. Try this instead and don't forget to free it using the same sort of loop.
int **resCap2 = calloc(1, n * sizeof(int *));
assert(resCap2);
for (i = 0; i < n; i++) {
resCap2[i] = calloc(1, n * sizeof(int));
assert(resCap2[i]);
}
This is a lot of space ie
(1000 * sizeof(int*) * (1000 * n * sizeof(int)))
I'm having problems by freeing the elements on my struct.
long code warning
typedef struct bingo
{
char board[5][5];
int* luckNum;
int* boardNum;
} bingo;
void update(bingo *pBingo,int num); //Function that gets a struct, number and checks if he is in the board, if it does he change it to "X"
int main(void)
{
srand(time(NULL));
int i, j, m, k, temp[75], *parr;
bingo player;
//For rellocating them later
if (!(player.luckNum = (int*) malloc(sizeof(int))))
{
printf("ERROR");
}
if (!(player.boardNum = (int*) malloc(sizeof(int))))
{
printf("ERROR");
}
//giving temp values of 1-75
for ( i = 0; i < 75; i++)
{
temp[i] = i + 1;
}
//Giving the player board random values of 1-75 without repeating the same number twice
for ( i = 0; i < 5; i++) //Passing on the rows
{
for (j = 0; j < 5; j++) //Passing on the columns
{
//
do
{
k = rand() % 75; //from 0-74
}
while (temp[k] == NULL); //while temp[k] is marked
player.board[i][j] = temp[k];
temp[k] = NULL; //NULL as a "flag" that marks the cell as taken (for not taking the same number twice)
player.luckNum=(int*) malloc(sizeof(int)*(i*j+j));
player.luckNum[i*j + j] = player.board[i][j];
}
}
//sets luckNum
for ( i = 0; i < 25; i++)
{
printf("%d ", player.luckNum[i]);
update(&player, player.luckNum[i]);
}
printf("\n");
for ( i = 0; i < 25; i++)
{
printf("%d",player.luckNum);
}
free(player.boardNum);
free(player.luckNum);
getchar();
return 0;
}
void update(bingo *pBingo, int num)
{
int i, j, k;
static int counter = 0,luckCounter = 25;
for (i = 0; i < 5; i++)
{
for (j = 0; j < 5; j++)
{
if (num == (int) (pBingo->board[i][j]))
{
pBingo->board[i][j] = 'X';
counter++;
pBingo->boardNum = (int*) realloc(pBingo->boardNum, sizeof(int)*counter);
pBingo->boardNum[counter] = num;
for (k = 0; k < luckCounter; k++)
{
if (pBingo->luckNum[k] == num)
{
num = pBingo->luckNum[k];
pBingo->luckNum[k] = pBingo->luckNum[luckCounter-1];
pBingo->luckNum[luckCounter-1] = num;
pBingo->luckNum = (int*) realloc(pBingo->luckNum, sizeof(int)*luckCounter);
luckCounter--;
}
}
}
}
}
}
Can anyone recognize what interrupts the free() function from freeing the memory?. I'm new to C and working on this code about good days so sorry for my ignorance about free() function, can anyone help me?
Ilan,
Don't be afraid to post your code with the necessary includes. First of all, are you heeding to the warnings of your compiler?
A few problem areas:
while (temp[k] == NULL)
You can research the difference between 0, NULL and '\0' but reserve the use of NULL for pointers. Also:
for ( i = 0; i < 25; i++)
{
printf("%d",player.luckNum);
}
Printf is expecting an integer and you're giving it a pointer. Finally, to address what I think is your problem, when you write "..interrupts the free() function from freeing the memory?" Do you mean your program simply not returning? If so then get rid of the final getchar(). You're still going to have at least one leak in this program. This address of this malloc:
if (!(player.luckNum = (int*) malloc(sizeof(int))))
will be lost as you assigned luck.Num a new address here without freeing the first:
player.luckNum=(int*) malloc(sizeof(int)*(i*j+j));
I have two arrays (representing rooms) with items that are traveling through the space. I found an interesting way to allocate the ram here in the forum. Here is what I am doing:
First I create an empty room with some default values.
After that I put some elements into it. There are two different items. An obstacle and an item that travels through the room. I have an iteration that runs for example 100 times and puts all items one coordinate further. The obstacles keep their position.
Every iteration has to do the following:
First it creates a new temporary room (new_room). It copies all obstacles because they stay at the same place(id = 3). Next, every item from the old room(room) gets his new coordinate in the new_room. After that I change the rooms, so room gets new_room. I have some big problems with the memory usage. I want to free the old new_room every time I create a new one with createRoomNew().In this implementation I get a segmentation fault. I think because of the function changeroom().
I am really confused right now because I am new to C.... I hope I pointed out what I mean. Thank you very much!
item_node ***room;
item_node ***room_new;
void createRoom(int x, int y, int z)
{
if (room == NULL) {
item_node *allElements = malloc(x * y * z * sizeof(item_node));
room = malloc(x * sizeof(item_node **));
for(int i = 0; i < x; i++)
{
room[i] = malloc(y * sizeof(item_node *));
for(int j = 0; j < y; j++)
{
room[i][j] = allElements + (i * y * z) + (j * z);
}
}
for (j = 0; j < x_format; j++) {
for (k = 0; k < y_format; k++) {
for (l = 0; l < z_format; l++) {
room[j][k][l].id = 3;
room[j][k][l].next = NULL;
}
}
}
}
}
void createRoomNew(int x, int y, int z)
{
if (room_new != NULL) {
for(int i = 0; i < x; i++)
{
free(room_new[i]);
}
free (room_new);
room_new = NULL;
}
if (room_new == NULL) {
item_node *allElements = malloc(x * y * z * sizeof(item_node));
room_new = malloc(x * sizeof(item_node **));
for(int i = 0; i < x; i++)
{
room_new[i] = malloc(y * sizeof(item_node *));
for(int j = 0; j < y; j++)
{
room_new[i][j] = allElements + (i * y * z) + (j * z);
}
}
}
for (j = 0; j < x_format; j++) {
for (k = 0; k < y_format; k++) {
for (l = 0; l < z_format; l++) {
if ((room[j][k][l].next) != NULL) {
if ((room[j][k][l].next->id) == 1) {
room_new[j][k][l] = room[j][k][l];
} else {
room_new[j][k][l].id = 3;
room_new[j][k][l].next = NULL;
}
}
else {
room_new[j][k][l].id = 3;
room_new[j][k][l].next = NULL;
}
}
}
}
}
void changeRoom(item_node *** newRoom)
{
room = newRoom;
}
Example call:
createRoom(200, 200, 200);
createRoomNew(200, 200, 200);
changeRoom(room_new);
createRoomNew(200, 200, 200);
changeRoom(room_new);
From the code it seems you think that when you do free, e.g. free(room_new) that room_new ends up being set to NULL. That is not the case
free() doesn't set a pointer to NULL (it can't), it is still pointing to wherever it was pointing just that the memory is no longer usable. You need to manually set the pointer to NULL after freeing.
I have a pointer variable int ***a in C. I'm passing it to a function as &a i.e reference. In the function I'm getting a pointer variable of type int ****a.
I'm allocating memory like this.
*a=(int***)malloc(no1*sizeof(int**));
some loop from 0 to no1
(*a)[++l]=(int**)malloc((no1+1)*sizeof(int*));
some loop from 0 to no1
(*a)[l][h]=(int*)malloc(2*sizeof(int));
This is only the time I allocated memory. The actual program is not given; no error here.
But when I'm going to do this:
(*a)[l][h][0]=no1;
It's giving me a "Segmentation Fault" error and I can't understand why.
UPDATE:
I have wrote a sample program which is to allocate the memory only. This is also giving "segmentation fault" error.
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
void allocate(int ****a)
{
int i,j,k;
if(((*a)=(int***)malloc(5*sizeof(int**)))==NULL)
{
printf("\nError in allocation of double pointer array\n");
exit(0);
}
for(i=0;i<5;i++)if(((*a)[i]=(int**)malloc(4*sizeof(int*)))==NULL)
{
printf("\nError in allocation of single pointer array on index [%d]\n",i);
exit(0);
}
for(i=0;i<5;i++)
for(j=0;j<4;i++)
if(((*a)[i][j]=(int*)malloc(3*sizeof(int)))==NULL)
{
printf("\nError in allocation of array on index [%d][%d]\n",i,j);
exit(0);
}
for(i=0;i<5;i++)
for(j=0;j<4;i++)
for(k=0;k<3;k++)
(*a)[i][j][k]=k;
}
main()
{
int ***a;
int i,j,k;
allocate(&a);
for(i=0;i<5;i++)
for(j=0;j<4;i++)
for(k=0;k<3;k++)
printf("\na[%d][%d][%d] = %d ",i,j,k,a[i][j][k]);
}
Revised code from question
Your code has:
for(i=0;i<5;i++)
for(j=0;j<4;i++)
several times. The second loop should be incrementing j, not i. Be very careful with copy'n'paste.
This code does not crash (but does leak).
#include <stdio.h>
#include <stdlib.h>
void allocate(int ****a);
void allocate(int ****a)
{
int i,j,k;
printf("allocate: 1B\n");
if(((*a)=(int***)malloc(5*sizeof(int**)))==NULL)
{
printf("\nError in allocation of double pointer array\n");
exit(0);
}
printf("allocate: 1A\n");
printf("allocate: 2B\n");
for(i=0;i<5;i++)
if(((*a)[i]=(int**)malloc(4*sizeof(int*)))==NULL)
{
printf("\nError in allocation of single pointer array on index [%d]\n",i);
exit(0);
}
printf("allocate: 2A\n");
printf("allocate: 3B\n");
for(i=0;i<5;i++)
for(j=0;j<4;j++)
if(((*a)[i][j]=(int*)malloc(3*sizeof(int)))==NULL)
{
printf("\nError in allocation of array on index [%d][%d]\n",i,j);
exit(0);
}
printf("allocate: 3A\n");
printf("allocate: 4B\n");
for(i=0;i<5;i++)
for(j=0;j<4;j++)
for(k=0;k<3;k++)
(*a)[i][j][k]=k;
printf("allocate: 4A\n");
}
int main(void)
{
int ***a;
int i,j,k;
allocate(&a);
for(i=0;i<5;i++)
for(j=0;j<4;j++)
for(k=0;k<3;k++)
printf("a[%d][%d][%d] = %d\n",i,j,k,a[i][j][k]);
}
Previous answers
Since you've not shown us most of the code, it is hard to predict how you're mishandling it, but equally, since you are getting a core dump, you must be mishandling something.
Here is some working code — not checked with valgrind since that is not available for Mac OS X 10.8 — that seems to work. The error recovery for allocation failure is not complete, and the function to destroy the fully allocated array is also missing.
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
static int ***allocate_3d_array(int no1, int ****a)
{
*a = (int***)malloc(no1 * sizeof(int**));
if (*a == 0)
return 0;
for (int l = 0; l < no1; l++)
{
if (((*a)[l]=(int**)malloc((no1+1)*sizeof(int*))) == 0)
{
while (l > 0)
free((*a)[--l]);
return 0;
}
}
for (int l = 0; l < no1; l++)
{
for (int h = 0; h < no1; h++)
{
if (((*a)[l][h]=(int*)malloc(2*sizeof(int))) == 0)
{
/* Leak! */
return 0;
}
}
}
for (int l = 0; l < no1; l++)
for (int h = 0; h < no1; h++)
for (int k = 0; k < 2; k++)
(*a)[l][h][k] = 10000 * l + 100 * h + k;
return *a;
}
int main(void)
{
int no1 = 5;
int ***a = 0;
int ***b = allocate_3d_array(no1, &a);
const char *pad[] = { " ", "\n" };
assert(b == a);
if (a != 0)
{
for (int l = 0; l < no1; l++)
for (int h = 0; h < no1; h++)
for (int k = 0; k < 2; k++)
printf("a[%d][%d][%d] = %.6d%s", l, h, k, a[l][h][k], pad[k]);
// free memory - added by harpun; reformatted by Jonathan Leffler
// Would be a function normally — see version 2 code.
for (int l = 0; l < no1; l++)
{
for (int h = 0; h < no1; h++)
free(a[l][h]);
free(a[l]);
}
free(a);
}
return 0;
}
Sample output:
a[0][0][0] = 000000 a[0][0][1] = 000001
a[0][1][0] = 000100 a[0][1][1] = 000101
a[0][2][0] = 000200 a[0][2][1] = 000201
a[0][3][0] = 000300 a[0][3][1] = 000301
a[0][4][0] = 000400 a[0][4][1] = 000401
a[1][0][0] = 010000 a[1][0][1] = 010001
a[1][1][0] = 010100 a[1][1][1] = 010101
a[1][2][0] = 010200 a[1][2][1] = 010201
a[1][3][0] = 010300 a[1][3][1] = 010301
a[1][4][0] = 010400 a[1][4][1] = 010401
a[2][0][0] = 020000 a[2][0][1] = 020001
a[2][1][0] = 020100 a[2][1][1] = 020101
a[2][2][0] = 020200 a[2][2][1] = 020201
a[2][3][0] = 020300 a[2][3][1] = 020301
a[2][4][0] = 020400 a[2][4][1] = 020401
a[3][0][0] = 030000 a[3][0][1] = 030001
a[3][1][0] = 030100 a[3][1][1] = 030101
a[3][2][0] = 030200 a[3][2][1] = 030201
a[3][3][0] = 030300 a[3][3][1] = 030301
a[3][4][0] = 030400 a[3][4][1] = 030401
a[4][0][0] = 040000 a[4][0][1] = 040001
a[4][1][0] = 040100 a[4][1][1] = 040101
a[4][2][0] = 040200 a[4][2][1] = 040201
a[4][3][0] = 040300 a[4][3][1] = 040301
a[4][4][0] = 040400 a[4][4][1] = 040401
Compare this with what you've got. You could add many more diagnostic print messages. If this doesn't help sufficiently, create an SSCCE (Short, Self-Contained, Correct Example) analogous to this that demonstrates the problem in your code without any extraneous material.
Version 2 of the code
This is a somewhat more complex version of the code that simulates memory allocation failures after N allocations (and a test harness that runs it with every value of N from 0 up to 35, where there are actually only 30 allocations for the array. It also includes code to release the array (similar to, but different from, the code that was edited into my answer by harpun. The interaction at the end with the line containing the PID means that I can check memory usage with ps in another terminal window. (Otherwise, I don't like programs that do that sort of thing — I suppose I should run the ps from my program via system(), but I'm feeling lazy.)
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static int fail_after = 0;
static int num_allocs = 0;
static void *xmalloc(size_t size)
{
if (fail_after > 0 && num_allocs++ >= fail_after)
{
fputs("Out of memory\n", stdout);
return 0;
}
return malloc(size);
}
static int ***allocate_3d_array(int no1, int ****a)
{
*a = (int***)xmalloc(no1 * sizeof(int**));
if (*a == 0)
return 0;
for (int l = 0; l < no1; l++)
{
if (((*a)[l]=(int**)xmalloc((no1+1)*sizeof(int*))) == 0)
{
for (int l1 = 0; l1 < l; l1++)
free((*a)[l1]);
free(*a);
*a = 0;
return 0;
}
}
for (int l = 0; l < no1; l++)
{
for (int h = 0; h < no1; h++)
{
if (((*a)[l][h]=(int*)xmalloc(2*sizeof(int))) == 0)
{
/* Release prior items in current row */
for (int h1 = 0; h1 < h; h1++)
free((*a)[l][h1]);
free((*a)[l]);
/* Release items in prior rows */
for (int l1 = 0; l1 < l; l1++)
{
for (int h1 = 0; h1 < no1; h1++)
free((*a)[l1][h1]);
free((*a)[l1]);
}
free(*a);
*a = 0;
return 0;
}
}
}
for (int l = 0; l < no1; l++)
for (int h = 0; h < no1; h++)
for (int k = 0; k < 2; k++)
(*a)[l][h][k] = 10000 * l + 100 * h + k;
return *a;
}
static void destroy_3d_array(int no1, int ***a)
{
if (a != 0)
{
for (int l = 0; l < no1; l++)
{
for (int h = 0; h < no1; h++)
free(a[l][h]);
free(a[l]);
}
free(a);
}
}
static void test_allocation(int no1)
{
int ***a = 0;
int ***b = allocate_3d_array(no1, &a);
const char *pad[] = { " ", "\n" };
assert(b == a);
if (a != 0)
{
for (int l = 0; l < no1; l++)
{
for (int h = 0; h < no1; h++)
{
for (int k = 0; k < 2; k++)
{
if (a[l][h][k] != l * 10000 + h * 100 + k)
printf("a[%d][%d][%d] = %.6d%s", l, h, k, a[l][h][k], pad[k]);
}
}
}
}
destroy_3d_array(no1, a);
}
int main(void)
{
int no1 = 5;
for (fail_after = 0; fail_after < 33; fail_after++)
{
printf("Fail after: %d\n", fail_after);
num_allocs = 0;
test_allocation(no1);
}
printf("PID %d - waiting for some data to exit:", (int)getpid());
fflush(0);
getchar();
return 0;
}
Note how painful the memory recovery is. As before, not tested with valgrind, but I take reassurance from harpun's test on the previous version.
Version 3 — Clean bill of health from valgrind
This code is very similar to the test in version 2. It fixes a memory leak in the clean-up when a memory allocation fails in the leaf level allocations. The program no longer prompts for inputs (much preferable); it takes an optional single argument that is the number of allocations to fail after. Testing with valgrind showed that with an argument 0-6, there were no leaks, but with argument 7 there was a leak. It didn't take long to spot the problem and fix it. (It's easier when the machine running valgrind is available — it was powered down over the long weekend for general site electrical supply upgrade.)
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
static int fail_after = 0;
static int num_allocs = 0;
static void *xmalloc(size_t size)
{
if (fail_after > 0 && num_allocs++ >= fail_after)
{
fputs("Out of memory\n", stdout);
return 0;
}
return malloc(size);
}
static int ***allocate_3d_array(int no1, int ****a)
{
*a = (int***)xmalloc(no1 * sizeof(int**));
if (*a == 0)
return 0;
for (int l = 0; l < no1; l++)
{
if (((*a)[l]=(int**)xmalloc((no1+1)*sizeof(int*))) == 0)
{
for (int l1 = 0; l1 < l; l1++)
free((*a)[l1]);
free(*a);
*a = 0;
return 0;
}
}
for (int l = 0; l < no1; l++)
{
for (int h = 0; h < no1; h++)
{
if (((*a)[l][h]=(int*)xmalloc(2*sizeof(int))) == 0)
{
/* Release prior items in current (partial) row */
for (int h1 = 0; h1 < h; h1++)
free((*a)[l][h1]);
/* Release items in prior (complete) rows */
for (int l1 = 0; l1 < l; l1++)
{
for (int h1 = 0; h1 < no1; h1++)
free((*a)[l1][h1]);
}
/* Release entries in first (complete) level of array */
for (int l1 = 0; l1 < no1; l1++)
free((*a)[l1]);
free(*a);
*a = 0;
return 0;
}
}
}
for (int l = 0; l < no1; l++)
for (int h = 0; h < no1; h++)
for (int k = 0; k < 2; k++)
(*a)[l][h][k] = 10000 * l + 100 * h + k;
return *a;
}
static void destroy_3d_array(int no1, int ***a)
{
if (a != 0)
{
for (int l = 0; l < no1; l++)
{
for (int h = 0; h < no1; h++)
free(a[l][h]);
free(a[l]);
}
free(a);
}
}
static void test_allocation(int no1)
{
int ***a = 0;
int ***b = allocate_3d_array(no1, &a);
const char *pad[] = { " ", "\n" };
assert(b == a);
if (a != 0)
{
for (int l = 0; l < no1; l++)
{
for (int h = 0; h < no1; h++)
{
for (int k = 0; k < 2; k++)
{
if (a[l][h][k] != l * 10000 + h * 100 + k)
printf("a[%d][%d][%d] = %.6d%s", l, h, k, a[l][h][k], pad[k]);
}
}
}
}
destroy_3d_array(no1, a);
}
int main(int argc, char **argv)
{
int no1 = 5;
int fail_limit = 33;
if (argc == 2)
fail_limit = atoi(argv[1]);
for (fail_after = 0; fail_after < fail_limit; fail_after++)
{
printf("Fail after: %d\n", fail_after);
num_allocs = 0;
test_allocation(no1);
}
return 0;
}
Version 4 — Fewer memory allocations
Update 2014-12-20
The code above makes a lot of memory allocations, which complicates the release and error recovery. Here is an alternative version that makes just 3 allocations, one for the vector of pointers to pointers, one for the array of pointers, and one for the array of integers. It then sets the pointers to point to the correct places in memory.
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
static int fail_after = 0;
static int num_allocs = 0;
static void *xmalloc(size_t size)
{
if (fail_after > 0 && num_allocs++ >= fail_after)
{
fputs("Out of memory\n", stdout);
return 0;
}
return malloc(size);
}
static int ***allocate_3d_array(int no1, int ****a)
{
int ***d0 = (int***)xmalloc(no1 * sizeof(int**));
int **d1 = (int **)xmalloc(no1 * no1 * sizeof(int *));
int *d2 = (int *)xmalloc(no1 * no1 * 2 * sizeof(int));
if (d0 == 0 || d1 == 0 || d2 == 0)
{
free(d0);
free(d1);
free(d2);
*a = 0;
return 0;
}
for (int l = 0; l < no1; l++)
{
d0[l] = &d1[l * no1];
for (int h = 0; h < no1; h++)
{
d0[l][h] = &d2[(l * no1 + h) * 2];
for (int k = 0; k < 2; k++)
d0[l][h][k] = l * 10000 + h * 100 + k;
}
}
*a = d0;
return *a;
}
static void destroy_3d_array(int ***a)
{
if (a != 0)
{
free(a[0][0]);
free(a[0]);
free(a);
}
}
static void test_allocation(int no1)
{
int ***a = 0;
int ***b = allocate_3d_array(no1, &a);
const char *pad[] = { " ", "\n" };
assert(b == a);
if (a != 0)
{
for (int l = 0; l < no1; l++)
{
for (int h = 0; h < no1; h++)
{
for (int k = 0; k < 2; k++)
{
if (a[l][h][k] != l * 10000 + h * 100 + k)
printf("Oops: a[%d][%d][%d] = %.6d%s", l, h, k, a[l][h][k], pad[k]);
}
}
}
}
destroy_3d_array(a);
}
int main(int argc, char **argv)
{
int no1 = 5;
int fail_limit = 4;
if (argc == 2)
fail_limit = atoi(argv[1]);
for (fail_after = 0; fail_after < fail_limit; fail_after++)
{
printf("Fail after: %d\n", fail_after);
num_allocs = 0;
test_allocation(no1);
}
return 0;
}
This has a clean bill of health with GCC 4.9.1 on Mac OS X 10.10.1, checked with valgrind version valgrind-3.11.0.SVN (built from an SVN tree with some necessary fixes for Mac OS X, but not enough suppressions).
The diagnostic print (starting with 'Oops') was triggered while I developed the answer; I had my pointer calculations wrong at the time.
Sorry, but, to be blunt: this is a horrid way of handling a 3D array: a double-nested loop with a bucketload of calls to malloc(), then triple-indirection to get a value at runtime. Yeuch! :o)
The conventional way of doing this (in the HPC community) is to use a one-dimensional array and do the index computation yourself. Suppose index i iterates over nx planes in the x direction, j iterates over ny pencils in the y direction, and k iterates over nz cells in the z direction. Then a pencil has nz elements, a plane has nz*ny elements, and the whole “brick” has nz*ny*nx elements. Thus, you can iterate over the whole structure with:
for(i=0; i<nx; i++) {
for(j=0; j<ny; j++) {
for(k=0; k<nz; k++) {
printf("a(%d,%d,%d) = %d\n", i, j, k, a[(i*ny+j)*nz+k]);
}
}
}
The advantage of this construction is that you can allocate it with a single call to malloc(), rather than a boatload of nested calls:
int *a;
a = malloc(nx*ny*nz*sizeof(int));
The construction x=a[i][j][k] has three levels of indirection: you have to fetch an address from memory, a, add an offset, i, fetch that address from memory, a[i], add an offset, j, fetch that address from memory, a[i][j], add an offset, k, and (finally) fetch the data, a[i][j][k]. All those intermediate pointers are wasting cache-lines and TLB entries.
The construction x=a[(i*ny+j)*nz+k] has one level of indirection at the expense of two additional integer multiplications: compute the offset, fetch address, 'a', from memory, compute and add the offset, (i*ny+j)*nz+k, fetch the data.
Furthermore, there is essentially no way whatsoever of improving the triple-indirection method's performance based on data-access patterns. If we were actually visiting every cell, we could do something like this to avoid some of the overhead of index computation.
ij = 0;
for(i=0; i<nx; i++) {
ii=i*ny;
for(j=0; j<ny; j++) {
ij=(ii+j)*nz;
for(k=0; k<nz; k++) {
printf("a(%d,%d,%d) = %d\n", i, j, k, a[ij+k]);
}
}
}
Depending on what you're doing, this may not be great either, and there all alternative layouts and indexing methods (such as Morton or Ahnenteufel indexing) that may be more suitable, depending on your access patterns. I'm not trying to give a complete treatise on 3D Cartesian grid representation or indexing, merely illustrate that a “three star” solution is very bad for numerous reasons.
By using (*a)[l][h][0] you are trying to de-reference a plain int and not a pointer.
use a[l][h][0] directly to assign any value to it.
I am making a program in the C90 standard using GCC in Ubuntu 10.04, that randomly generates a hand of 5 card structs and calculates if the hand is a flush, straight, etc.
My function to calculate straights is:
int isStraight(card hand[]) {
int i, count = 1, result = 0;
for (i = 0; i < HAND_SIZE-1; i++) {
if (hand[i].pips == ((hand[i+1].pips) + 1)) {
count++;
}
}
if (count == HAND_SIZE)
result = 1;
return result;
}
My main function:
int main(void) {
int i, j;
int numHands = 0;
int flushCount = 0;
int straightCount = 0;
int xOfAKindCount = 0;
int straightFlushCount = 0;
int fullHouseCount = 0;
int isTwoPairCount = 0;
card deck[DECKSZ] = {0};
card hand[HAND_SIZE] = {0};
stack deckStack = {0};
stack handStack = {0};
initDeck(deck);
shuffleDeck(deck);
reset(&deckStack);
for (i = 0; i < DECKSZ; i++) {
push(deck[i], &deckStack);
}
do {
reset(&handStack);
for (i = 0; i < HAND_SIZE; i++) {
push(pop(&deckStack), &handStack);
if (isEmpty(&deckStack)) {
reset(&handStack);
shuffleDeck(deck);
reset(&deckStack);
for (j = 0; j < DECKSZ; j++) {
push(deck[j], &deckStack);
}
}
hand[i] = handStack.s[i];
}
numHands += 1;
arrangeHand(hand);
flushCount += isFlush(hand);
straightCount += isStraight(hand);
xOfAKindCount += isXOfAKind(hand, 2, 0);
straightFlushCount += isStraightFlush(hand);
fullHouseCount += isFullHouse(hand);
isTwoPairCount += isTwoPair(hand);
printf("Flushes:%d Straights:%d SF's:%d Number of Hands:%d\r",
flushCount, straightCount, straightFlushCount, numHands);
} while (1);
printf("\n");
return EXIT_SUCCESS;
}
My issue is my variable declared inside my function, result, is never set to 1 to indicate whether or not the hand is a straight, which therefore means my straightCount variable always remains at a value of zero. I do not have access to a debugger and in my mind the code I have makes sense. I'm new to programming in C, so if anybody could help me point out what is wrong with my function, I'd appreciate it. Thanks!
int isStraight(card hand[]) {
int step = 0;
for(int i = 1;i < HAND_SIZE; i++)
if(hand[i].pip != hand[i-1].pip+1)
/* Substitute step with i!=1 if over-edge invalid */
if(step || hand->pip != 1 || hand[i].pip != hand[i-1].pip+13-HAND_SIZE)
return 0;
else
step = 1;
return 1;
}
Right, after reading the code again, there are not enogh cards...
for (i = 0; i < HAND_SIZE-1; ++i)
Then you care counting pairs, not just individual cards, so
If (count == HAND_SIZE-1)
for (i = 0; i < HAND_SIZE-1; i++) { means that you are testing HAND_SIZE-1 pairs (which is correct), with i from from 0 to HAND_SIZE-2, so count will never be HAND_SIZE.
You just need to change your test to if (count == HAND_SIZE-1)
Assuming that (a) pip values are 1=Ace, 2=Deuce, ... and (b) the hand is sorted before being passed to the function, and (c) hands are exactly five cards, here's a quick one:
int isStraight(card hand[]) {
int i;
// Handle Broadway special case
if (hand[0].pips == 13 && hand[1].pips == 12 && hand[2].pips == 11 &&
hand[3].pips == 10 && hand[4].pips == 1) return 1;
// This will handle the rest
for (i = 0; i < (HAND_SIZE-1); i += 1) {
if (hand[i].pips != hand[i+1].pips) return 0;
}
return 1;
}
Also, I wouldn't use a structure for cards. Using a single integer is much faster and more versatile. Check out http://etceterology.com/blog/2013/5/23/representing-playing-cards-in-software