Extra edge in my list? - c

I'm writing code to create a matrix out of a list of edges.
However, when I run said code, I get a "phantom edge" that is not in the input data, which goes on to screw up the rest of my program. The edge is 9,2 in the matrix, or 8,1 in elemental code form.
All elements in the matrix are initialized to 0 before hand.
Here is the input data to do with the matrix:
1 2
1 8
2 8
3 5
3 1
4 5
4 6
5 2
5 9
6 4
6 8
7 4
7 10
8 4
8 6
9 4
9 5
10 7
10 3
Here are the functions that handle the input:
void displayMatrix(int **matrix, int numberVertices){ //function displays the matrix
int i, j;
for(i=0; i<numberVertices; i++) //go through eveyr element
{
for(j=0; j<numberVertices; j++)
{
printf("%d ", matrix[i][j]); //print element
}
printf("\n");
}
printf("\n\n");
}
void inputMatrix(FILE *fp, int ** matrix) //file places value 1 into matrix if edge exists for the adjacency matrix
{
int e1, e2;
while(!feof(fp)) //continue to the end of the file
{
fscanf(fp, "%d %d", &e1, &e2); //get pairs
e1 = e1 - 1; //adjust the edges for array use
e2 = e2 - 1;
matrix[e1][e2] = 1; //place value 1 into appropriate location in adjacency matrix
}
fclose(fp); //close the file connection
}
0 1 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 1 0 0
1 0 0 0 1 0 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 1 0 0 0 0 0 0 1 0
0 0 0 1 0 0 0 1 0 0
0 0 0 1 0 0 0 0 0 1
0 0 0 1 0 1 0 0 0 0
0 *1 0 1 1 0 0 0 0 0
0 0 1 0 0 0 1 0 0 0
*the entry that should not exist, not in the input data

The problem is that you're looping one more additional time than necessary, causing fscanf to fail before the first conversion and thus leaving e1 and e2 as they were from the prior read. As it turns out, the last entry has e1 set to 10 and e2 to 3, so e1 becomes 9 and e2 becomes 2, thus causing your phantom edge.
The cause of this additional loop is because your loop condition doesn't do what you think it does. feof checks if the end-of-file flag has been set, and this can only be set when attempting to read at the end of the file. Since you're checking for end-of-file before your read, you're not actually picking up on this until the next iteration, thus you loop an additional time. The proper correction is very simple; just continue until fscanf results in EOF.
while (fscanf(fp, "%d %d", &e1, &e2) != EOF)
{
matrix[e1 - 1][e2 - 1] = 1;
}

As pointed out in the comments, you're not testing for errors in fscanf.
In particular, you have not yet reached the end of file after reading 10 3, presumably because a newline was encountered.
However, in the next time around fscanf will return zero. Then you subtract 1 from those values (which were not read) to get 9 2.
You can make sure that two integers were read by doing this:
if( 2 != fscanf(fp, "%d %d", &e1, &e2) ) break;

You can try this:
fscanf(fp, "%d %d\n", &e1, &e2);
When you finish the last two digit, there is one more \n,the loop have to continue,this will make trouble

Related

2D array - I want to find which columns have 1s in them in each row

My input looks like this :
15 5
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
0 0 0 0 0
0 0 0 0 0
1 0 0 0 0
0 1 0 1 0
0 0 1 0 0
0 0 0 0 1
0 0 0 0 0
0 0 0 0 0
0 1 0 0 0
1 0 0 0 1
0 0 1 0 0
0 0 0 1 0
The first row contains the number of rows and columns of my array. And basically I want to find out where these 1s are in the array.
So in the first 3 rows i want to get 3, in the 7th 1, and in the 8th, i want to get 2 3 etc..
My code looks like this so far
#include <stdio.h>
int main() {
int row, column;
FILE* input;
FILE* output;
input = fopen("input.txt", "r");
if (input == 0) {
printf("ERROR couldn't open input.txt");
return 1;
}
if (! fscanf(input, "%d %d", &row, &column)) {
printf("ERROR not recognised value");
fclose(input);
return 2;
}
output = fopen("output.txt", "w");
int meteor[row][column];
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
fscanf(input, "%d", &meteor[i][j]);
}
}
int sum;
int loc[row];
for (int i = 0; i < row; i++) {
sum = 0;
for (int j = 0; j < column; j++) {
sum += meteor[i][j];
if (meteor[i][j] == 1) {
loc[i] = (j + 1);
}
}
printf("%d %d\n", loc[i], sum);
}
fclose(input);
fclose(output);
return 0;
}
My output is this :
3 1
3 1
3 1
0 0
-1 0
1 1
4 2
3 1
5 1
0 0
4214921 0
2 1
5 2
3 1
4 1
The first column shows some of the locations, the second shows how many 1s are in the row, but it all fails when there are only 0s in the row or there is more than one 1. And also I would like to store these values.
You need to initialize loc[].. If you look carefully at your code, you only populate it on the condition of if (meteor[i][j] == 1)... but you print it for every index of i. which would print uninitialized memory (i.e. unknown).
To answer the second part of your question, if you want to store the "sum". Simply make loc[] a 2d array just like meteor, but with 2 columns (row and sum). i.e. int loc[row][2].. making sure to initialize both columns of course :)

Segfault while allotting 2D array using double dimensional pointer

I'm currently working on a codechef practice problem http://www.codechef.com/problems/STEPUP#
I'm trying to set up a 2D array using pointers to accept the data and enter in into the 2D array as i receive it using scanf.
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char **argv)
{
int m,n,i,k,j;
int ex;
scanf("%d",&ex);
for(i=0;i<ex;i++)
{
int **edgegraph=NULL,temp1,temp2;
scanf("%d %d",&n,&m);
edgegraph=malloc(m*sizeof(int));
for(k=0;k<m;k++)
{
*(edgegraph+k)=malloc(m*sizeof(int));
if(!*(edgegraph+k))
exit(0);
}
for(k=0;k<m;k++)
{
scanf("%d %d",&temp1,&temp2);
*(*(edgegraph+m*temp1)+temp2)=1;
}
for(i=0;i<m;i++)
{
for(j=0;j<m;j++)
printf("%d ",*(*(edgegraph+m*i)+j));
printf("\n");
}
}
}
The error i get is
(gdb) run
Starting program: /home/vishwa/codechef/valid
2
2 2
1 2
Program received signal SIGSEGV, Segmentation fault.
0x000000000040079d in main (argc=1, argv=0x7fffffffded8) at validedge.c:24
24 *(*(edgegraph+m*temp1)+temp2)=1;
(gdb) quit
What I intend to do is create an m*m matrix, set all valid edges to 1 and then sort in ascending order of number of edges. I'm unsure if this will solve the problem, but would like to know where I'm messing up.
You malloc the wrong number of bytes: edgegraph=malloc(m*sizeof(int)); should have malloc(m * sizeof(int *)); . To avoid this sort of error you can use the following pattern:
ptr = malloc( N * sizeof *ptr );
which always allocates N of whatever ptr is a pointer to.
Next, the syntax x[y] is much simpler to read than *(x+y) especially when the expressions get complicated. Using that syntax would have avoided the mistake dconman points outs. You seem to have put an extra m * into your calculation where it is not required.
Also you mix up m and n later in your code. To avoid this sort of error, use more descriptive variable names.
So a fixed version of your allocation code could look like:
if ( 2 != scanf("%d %d",&num_edges, &num_vertices) )
exit(EXIT_FAILURE);
edgegraph = malloc( num_vertices * sizeof *edgegraph );
for (int vertex = 0; vertex < num_vertices; ++vertex)
{
edgegraph[vertex] = malloc( num_vertices * sizeof **edgegraph );
if ( edgegraph[vertex] == NULL )
exit(EXIT_FAILURE);
}
Note that it is possible to replace that malloc series with a single allocation:
int (*edgegraph)[num_vertices] = malloc( num_vertices * sizeof *edgegraph );
Moving onto your code to read edges. You wrote for(k=0;k<m;k++) however I think you meant n there. Using more descriptive variable names and the x[y] syntax:
for(int edge = 0; edge < num_edges; ++edge)
{
if ( 2 != scanf("%d %d",&temp1,&temp2) )
exit(EXIT_FAILURE);
if ( temp1 < 0 || temp1 >= num_vertices || temp2 < 0 || temp2 >= num_vertices )
exit(EXIT_FAILURE); // maybe display an error message
edgegraph[temp1][temp2] = 1;
edgegraph[temp2][temp1] = 1; // add this if undirected graph!
}
Now the final loop, for(i=0;i<m;i++). You have used the same variable i as control variable for this loop and for your outer loop. To avoid this sort of error, use scoped control variables:
for (int i = 0; i < num_edges; ++i)
Finally you will need to free the memory you malloc'd at the end of each time around the outer loop.
You are so close: lose the m* in your expressions to access an array element. Remember, you set up your 2d array as an array of rows, each with its own pointer (you allocated each independently).
*(*(edgegraph+m*temp1)+temp2)=1;
should be
*(*(edgegraph+temp1)+temp2)=1;
And the same change where you do that later in your code.
Is there a reason you are not using array indices?
EDIT
here is my input
2
10
10
4 3
4 9
7 3
3 7
4 3
4 5
7 4
3 5
9 0
5 2
And I got this 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 1 0 1 0 0
0 0 0 1 0 1 0 0 0 1
0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 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

Using C, While initializing an array of structs, it seems like the first column, and the last column are overlooping

When main runs, I've been getting this output. The first columns being somehow confused with the last one, even though it's specifically initialized.
0 0 0 0 0 0 4 3 13 3 3 0 0 0 0 0 0
0 0 0 0 0 4 0 0 5 0 0 2 0 0 0 0 0
0 0 0 0 4 0 0 0 5 0 0 0 2 0 0 0 0
0 0 0 18 0 0 0 0 5 0 0 0 0 17 0 0 0
0 0 4 0 2 0 7 12 19 12 3 0 8 0 2 0 0
0 4 0 0 0 0 0 0 5 0 0 0 0 0 0 2 0
0 0 0 0 5 0 0 0 5 0 0 0 5 0 0 0 2
2 0 0 0 11 0 0 0 5 0 0 0 11 0 0 0 1
1 7 7 7 20 7 7 7 14 7 7 7 20 7 7 7 1
1 0 0 0 11 0 0 0 5 0 0 0 11 0 0 0 1
1 0 0 0 1 0 0 0 5 0 0 0 1 0 0 0 0
0 6 0 0 0 0 0 0 5 0 0 0 0 0 0 8 0
0 0 6 0 4 0 7 12 19 12 3 0 6 0 8 0 0
0 0 0 15 0 0 0 0 5 0 0 0 0 16 0 0 0
0 0 0 0 6 0 0 0 5 0 0 0 8 0 0 0 0
0 0 0 0 0 6 0 0 5 0 0 8 0 0 0 0 0
0 0 0 0 0 0 7 7 7 7 8 0 0 0 0 0 0
motion.h
struct square{
int directions;
int isRobotHere;
int isMultipleDirections;
int printable;
};
typedef struct square Square;
struct robot{
int robotx;
int roboty;
int robotz;
int destinationx;
int destinationy;
int destinationz;
};
typedef struct robot Robot;
enum direction{North, NorthWest, West, SouthWest, South, SouthEast, East, NorthEast};
Square firstfloor[16][16];
Square secondfloor[16][16];
void printbothfloors();
void initializeArrays();
initializeArrays.c
#include <stdio.h>
#include "motion.h"
void initializeArrays(){
firstfloor[6][0].directions=5;
firstfloor[7][0].directions=5;
firstfloor[8][0].directions=14;
firstfloor[9][0].directions=5;
firstfloor[10][0].directions=6;
firstfloor[11][1].directions=6;
firstfloor[12][2].directions=6;
firstfloor[13][3].directions=15;
firstfloor[14][4].directions=6;
firstfloor[15][5].directions=6;
firstfloor[16][6].directions=7;
firstfloor[16][7].directions=7;
firstfloor[16][8].directions=7;
firstfloor[16][9].directions=7;
firstfloor[16][10].directions=8;
firstfloor[15][11].directions=8;
firstfloor[14][12].directions=8;
firstfloor[13][13].directions=16;
firstfloor[12][14].directions=8;
firstfloor[11][15].directions=8;
firstfloor[10][16].directions=1;
firstfloor[9][16].directions=1;
firstfloor[8][16].directions=1;
firstfloor[7][16].directions=1;
firstfloor[6][16].directions=2;
firstfloor[5][15].directions=2;
firstfloor[4][14].directions=2;
firstfloor[3][13].directions=17;
firstfloor[2][12].directions=2;
firstfloor[1][11].directions=2;
firstfloor[0][10].directions=3;
firstfloor[0][9].directions=3;
firstfloor[0][8].directions=13;
firstfloor[0][7].directions=3;
firstfloor[0][6].directions=4;
firstfloor[1][5].directions=4;
firstfloor[2][4].directions=4;
firstfloor[3][3].directions=18;
firstfloor[4][2].directions=4;
firstfloor[5][1].directions=4;
firstfloor[1][8].directions=5;
firstfloor[2][8].directions=5;
firstfloor[3][8].directions=5;
firstfloor[4][8].directions=19;
firstfloor[5][8].directions=5;
firstfloor[6][8].directions=5;
firstfloor[7][8].directions=5;
firstfloor[8][8].directions=14;
firstfloor[9][8].directions=5;
firstfloor[10][8].directions=5;
firstfloor[11][8].directions=5;
firstfloor[12][8].directions=19;
firstfloor[13][8].directions=5;
firstfloor[14][8].directions=5;
firstfloor[15][8].directions=5;
firstfloor[8][1].directions=7;
firstfloor[8][2].directions=7;
firstfloor[8][3].directions=7;
firstfloor[8][4].directions=20;
firstfloor[8][5].directions=7;
firstfloor[8][6].directions=7;
firstfloor[8][7].directions=7;
firstfloor[8][9].directions=7;
firstfloor[8][10].directions=7;
firstfloor[8][11].directions=7;
firstfloor[8][12].directions=20;
firstfloor[8][13].directions=7;
firstfloor[8][14].directions=7;
firstfloor[8][15].directions=7;
firstfloor[7][4].directions=11;
firstfloor[9][4].directions=11;
firstfloor[4][7].directions=12;
firstfloor[4][9].directions=12;
firstfloor[12][7].directions=12;
firstfloor[12][9].directions=12;
firstfloor[7][12].directions=11;
firstfloor[9][12].directions=11;
firstfloor[4][4].directions=2;
firstfloor[4][6].directions=7;
firstfloor[4][10].directions=3;
firstfloor[4][12].directions=8;
firstfloor[6][4].directions=5;
firstfloor[6][12].directions=5;
firstfloor[10][4].directions=1;
firstfloor[10][12].directions=1;
firstfloor[12][4].directions=4;
firstfloor[12][6].directions=7;
firstfloor[12][10].directions=3;
firstfloor[12][12].directions=6;
firstfloor[11][0].directions=0;
firstfloor[5][16].directions=0;
}
printbothfloors.c
#include <stdio.h>
#include <stdlib.h>
#include "motion.h"
void printbothfloors(){
// printf("printfloor is running");
int upper, lower, i, j;
printf("%4d %4d %4d %4d %4d", firstfloor[6][0].directions, firstfloor[7][0].directions, firstfloor[8][0].directions, firstfloor[9][0].directions, firstfloor[10][0].directions);
printf("%4d %4d %4d %4d %4d", firstfloor[6][16].directions, firstfloor[7][16].directions, firstfloor[8][16].directions, firstfloor[9][16].directions, firstfloor[10][16].directions);
printf("FIRST FLOOR");
printf("\n-");
/* The next for loop prints out the upper edge */
for (upper = 0; upper < 18; upper++){
printf("----");
}
printf("\n");
/*The next for loop prints out the floor, every element is 4 digits wide */
for (i = 0; i <= 16; i++){
printf("|");
for(j = 0; j <= 16; j++){
printf("%4d", firstfloor[i][j].directions);
}
printf(" |\n");
}
/* The next for loop prints out the lower edge */
for (lower = 0; lower < 18; lower++){
printf("----");
}
printf("-\n");
/*
printf("SECOND FLOOR");
// printf("printfloor is running");
printf("\n-----");
// The next for loop prints out the upper edge
for (upper = 0; upper < 17; upper++){
printf("----");
}
printf("\n");
//The next for loop prints out the floor, every element is 4 digits wide
for (i = 0; i <= 16; i++){
printf("|");
for(j = 0; j <= 16; j++){
printf("%4d", secondfloor[i][j].directions);
}
printf(" |\n");
}
// The next for loop prints out the lower edge
for (lower = 0; lower < 17; lower++){
printf("----");
}
printf("-----\n");
*/
}
prog2.c
#include <stdio.h>
#include <stdlib.h>
#include "motion.h"
//#include "printbothfloors.h"
int main(){
int row = 0;
int column = 0;
initializeArrays();
// printbothfloors();
/*
for (row=0; row < 17; row++){
for (column=0; column < 17; column++){
// firstfloor[row][column].directions=0;
// secondfloor[row][column].directions=5;
//firstfloor[i][j].isRobotHere=0;
//secondfloor[i][j].isRobotHere=0;
//firstfloor[i][j].isMultipleDirections=0;
//secondfloor[i][j].isMultipleDirections=0;
}
}
firstfloor[6][0].directions=5;
firstfloor[7][0].directions=5;
firstfloor[8][0].directions=14;
firstfloor[9][0].directions=5;
firstfloor[10][0].directions=6;
firstfloor[11][1].directions=6;
firstfloor[12][2].directions=6;
firstfloor[13][3].directions=15;
firstfloor[14][4].directions=6;
firstfloor[15][5].directions=6;
firstfloor[16][6].directions=7;
firstfloor[16][7].directions=7;
firstfloor[16][8].directions=7;
firstfloor[16][9].directions=7;
firstfloor[16][10].directions=8;
firstfloor[15][11].directions=8;
firstfloor[14][12].directions=8;
firstfloor[13][13].directions=16;
firstfloor[12][14].directions=8;
firstfloor[11][15].directions=8;
firstfloor[10][16].directions=1;
firstfloor[9][16].directions=1;
firstfloor[8][16].directions=1;
firstfloor[7][16].directions=1;
firstfloor[6][16].directions=2;
firstfloor[5][15].directions=2;
firstfloor[4][14].directions=2;
firstfloor[3][13].directions=17;
firstfloor[2][12].directions=2;
firstfloor[1][11].directions=2;
firstfloor[0][10].directions=3;
firstfloor[0][9].directions=3;
firstfloor[0][8].directions=13;
firstfloor[0][7].directions=3;
firstfloor[0][6].directions=4;
firstfloor[1][5].directions=4;
firstfloor[2][4].directions=4;
firstfloor[3][3].directions=18;
firstfloor[4][2].directions=4;
firstfloor[5][1].directions=4;
firstfloor[1][8].directions=5;
firstfloor[2][8].directions=5;
firstfloor[3][8].directions=5;
firstfloor[4][8].directions=19;
firstfloor[5][8].directions=5;
firstfloor[6][8].directions=5;
firstfloor[7][8].directions=5;
firstfloor[8][8].directions=14;
firstfloor[9][8].directions=5;
firstfloor[10][8].directions=5;
firstfloor[11][8].directions=5;
firstfloor[12][8].directions=19;
firstfloor[13][8].directions=5;
firstfloor[14][8].directions=5;
firstfloor[15][8].directions=5;
firstfloor[8][1].directions=7;
firstfloor[8][2].directions=7;
firstfloor[8][3].directions=7;
firstfloor[8][4].directions=20;
firstfloor[8][5].directions=7;
firstfloor[8][6].directions=7;
firstfloor[8][7].directions=7;
firstfloor[8][9].directions=7;
firstfloor[8][10].directions=7;
firstfloor[8][11].directions=7;
firstfloor[8][12].directions=20;
firstfloor[8][13].directions=7;
firstfloor[8][14].directions=7;
firstfloor[8][15].directions=7;
firstfloor[7][4].directions=11;
firstfloor[9][4].directions=11;
firstfloor[4][7].directions=12;
firstfloor[4][9].directions=12;
firstfloor[12][7].directions=12;
firstfloor[12][9].directions=12;
firstfloor[7][12].directions=11;
firstfloor[9][12].directions=11;
firstfloor[4][4].directions=2;
firstfloor[4][6].directions=7;
firstfloor[4][10].directions=3;
firstfloor[4][12].directions=8;
firstfloor[6][4].directions=5;
firstfloor[6][12].directions=5;
firstfloor[10][4].directions=1;
firstfloor[10][12].directions=1;
firstfloor[12][4].directions=4;
firstfloor[12][6].directions=7;
firstfloor[12][10].directions=3;
firstfloor[12][12].directions=6;
firstfloor[11][0].directions=0;
firstfloor[5][16].directions=0;
*/
// for (i = 0; i < 17; i++){
// firstfloor
// printbothfloors();
// pbf_entrypoints();
/*
row = 0;
column = 0;
while (i < 17){
firstfloor[i][8] = 1;
secondfloor[i][8] = 1;
firstfloor[8][i] = 1;
secondfloor[8][i] = 1;
i++;
}
*/
printf("Function got here");
printbothfloors();
return 0;
}
Valid indices for Type arr[N] are between 0 and N-1.
This goes for any Type and for any number of dimensions.
Indexes in C start at 0, so if you declare an array to have 16 elements, valid indexes start from 0 and end at 15.
16 boxes, numbered 0 to 15:
---------------------------------------------------------------------------------
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
---------------------------------------------------------------------------------
Accessing an element outside of this range (e.g. by using the index -1 or 16) invokes undefined behaviour.
Both the first answers are correct, I'll add some examples from your code.
firstfloor[6][16].directions
firstfloor[x][y], has been initialized as firstfloor[16][16] meaning the values x and y can can from 0 to 15. The numbering system is 0 based, a hang-over from Java's C language ancestry. 0-15 covers 16 elements.
/*The next for loop prints out the floor, every element is 4 digits wide */
for (i = 0; i <= 16; i++){
printf("|");
for(j = 0; j <= 16; j++){
printf("%4d", firstfloor[i][j].directions);
}
printf(" |\n");
}
The two for loops, start correctly at i = 0 and should only continue while i < 16 or if you prefer i <= 15.
At the moment I'm personally jumping between Java, C and Python, so someone might correct me in this, but calling firstfloor[6][16] if it does not generate an array out-of-bounds error, will give you the same result as firstfloor[7][0]. This might explain why you are observing the first columns being confused with the last.
Good luck :-)

Generate Binary Sequence

I want to generate permutations of string of 5 0s followed by the permutations of 4 0s and a single 1, followed by the permutations of 3 0s with 2 1s etc? My code is as follows:
#include<stdio.h>
int main(){
int i,j,k,l,s[5];
for(i=0;i<5;i++)
s[i]=0;
for(k=0;k<5;k++)
printf("%d ",s[k]);
printf("\n");
printf("---------------------------------------------\n");
for(i=0;i<5;i++){
for(j=0;j<5;j++)
if(i==j)
s[j]=1;
else
s[j]=0;
for(k=0;k<5;k++)
printf("%d ",s[k]);
printf("\n");
}
printf("---------------------------------------------\n");
for(i=0;i<5;i++){
for(k=0;k<5;k++)
s[k]=0;
s[i]=1;
for(j=i+1;j<5;j++){
s[j]=1;
for(k=0;k<5;k++)
printf("%d ",s[k]);
printf("\n");
for(k=j;k<5;k++)
s[k]=0;
}
}
printf("---------------------------------------------\n");
for(i=0;i<5;i++){
for(j=i+1;j<5;j++){
for(k=0;k<5;k++)
s[k]=0;
s[i]=1;
s[j]=1;
for(l=j+1;l<5;l++){
s[l]=1;
for(k=0;k<5;k++)
printf("%d ",s[k]);
printf("\n");
for(k=l;k<5;k++)
s[k]=0;
}
}
}
}
So output is
0 0 0 0 0
---------------------------------------------
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1
---------------------------------------------
1 1 0 0 0
1 0 1 0 0
1 0 0 1 0
1 0 0 0 1
0 1 1 0 0
0 1 0 1 0
0 1 0 0 1
0 0 1 1 0
0 0 1 0 1
0 0 0 1 1
---------------------------------------------
1 1 1 0 0
1 1 0 1 0
1 1 0 0 1
1 0 1 1 0
1 0 1 0 1
1 0 0 1 1
0 1 1 1 0
0 1 1 0 1
0 1 0 1 1
0 0 1 1 1
Output is ok. However in my code I use
different for loops for different cases.
Is it possible to use better approach so
that length of the code is reduced?
One approach follows. This solution needs O(n) space and each output string requires O(n) time.
#include <stdio.h>
#include <stdlib.h>
char *buf;
// Print combinations of m 1's in a field of n 0/1's starting at s.
void print_combinations(char *s, int n, int m)
{
// If there is nothing left to append, we are done. Print the buffer.
if (m == 0 && n == 0) {
*s = '\0';
printf("%s\n", buf);
return;
}
// Cut if there are more 1's than positions left or negative numbers.
if (m > n || m < 0 || n < 0) return;
// Append a 0 and recur to print the rest.
*s = '0';
print_combinations(s + 1, n - 1, m);
// Now do the same with 1.
*s = '1';
print_combinations(s + 1, n - 1, m - 1);
}
int main(void)
{
int n = 5;
buf = malloc(n + 1);
for (int m = 0; m <= n; m++) {
print_combinations(buf, n, m);
printf("-----\n");
}
return 0;
}
You could use a recursive function like so - you don't have to print the result when finished, you could add it to a list etc.
The function works by starting with an empty string. At each step you add one more character - in this case you add either a 0 or a 1.
If a 1 is added we account for this by decrementing the ones value on the next call to the function. (In a more general case you could pass a list of all the elements to be permuted - then the process would be to pick from this list, add it to your permutation and remove it from the list. You repeat that until the list is empty and you have permuted all of the elements in the list.)
When the string reaches the desired length we have finished and so we return.
#include <stdio.h>
void recurse(char *str, int length, int maxLength, int ones)
{
if (length == maxLength)
{
// we are finished
printf("%s\n", str);
return;
}
if (ones > 0)
{
// put a 1 into the new string
str[length] = '1';
recurse(str, length + 1, maxLength, ones - 1);
}
if (ones < maxLength - length)
{
// there are still spaces for 0s
// put a 0 into the string
str[length] = '0';
recurse(str, length + 1, maxLength, ones);
}
}
int main()
{
const int maxLength = 5;
char buffer[maxLength + 1];
buffer[maxLength] = 0;
int ones;
for (ones = 0; ones <= maxLength; ones++)
{
printf("Ones: %i\n", ones);
recurse(buffer, 0, maxLength, ones);
printf("\n");
}
return 0;
}
The output looks like this:
Ones: 0
00000
Ones: 1
10000
01000
00100
00010
00001
Ones: 2
11000
10100
10010
10001
01100
01010
01001
00110
00101
00011
Ones: 3
11100
11010
11001
10110
10101
10011
01110
01101
01011
00111
Ones: 4
11110
11101
11011
10111
01111
Ones: 5
11111
Finally, unless you really want to/need to learn/use C, I would recommend using C++ because you get really nice features like std::vector and std::set and so many other things which will make your life so much easier. I would have written this completely different in C++.

Sending blocks of 2D array rows using MPI in C

I am trying to do a matrix multiplication using MPI in C. (c <= a*b)
I am running the following code on 4 nodes. All the matrices are 8*8 in size.
(num of rows in a matrix % num of nodes == 0)
matrix b[][] is broadcast so all the nodes get the same copy. For matrix a[][], instead of broadcasting, I want to send only the set of rows that is needed by each node.
But when I run the following code and print the matrix a[][] after MPI_Recv() worker nodes print 0s instead of the values assigned in the master node.
Can you point out what am I doing wrong here?
#include <stdio.h>
#include "mpi.h"
#include "matrix.c" // matrix definitions and matrix operation functions are here
int main(int argc, char *argv[])
{
MPI_Status status;
int num, rank, size, tag, high,low,i;
int offset, tmphigh,rows;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
rows=MAX/size; // MAX is the length(=height) of the matrices
tag = 201;
low=rank*rows;
high=low+rows;
if (rank == 0) {
fillMatrix(b,MAX);
fillMatrix(a,MAX);
}
MPI_Bcast(&b[0][0],MAX*MAX,MPI_INT,0,MPI_COMM_WORLD);
if(rank==0){
for(i=1;i<size;i++){
offset=i*rows;
MPI_Send(&a[offset][0],rows*MAX,MPI_INT,i,tag,MPI_COMM_WORLD);
}
}else{
MPI_Recv(&a[low][0],rows*MAX,MPI_INT,0,tag,MPI_COMM_WORLD,&status);
}
printMatrix(a,MAX);
MPI_Finalize();
return 0;
}
here is how matrices are created
int a[MAX][MAX], b[MAX][MAX], c[MAX][MAX];
int len; //(edited after Jeremy W. Sherman's comment )
//this was the reason that caused this problem. changing this to int len=MAX; solved the problem
void fillMatrix(int (*matrix)[len], int len){
int i=0,j=0;
for(i=0;i<len;i++){
for(j=0;j<len;j++){
matrix[i][j]=j;
}
}
//printMatrix(matrix,len);
}
Thank You.
The problem might lie printMatrix() and fillMatrix(). clang refused to compile your definition of fillMatrix():
so_mpi.c:22:31: error: use of undeclared identifier 'len'
void fillMatrix(int (*matrix)[len], int len){
^
Dropping len from the prototype just creates another problem:
so_mpi.c:26:19: error: subscript of pointer to incomplete type 'int []'
matrix[i][j]=j;
~~~~~~^
What did work was this:
void fillMatrix(int *matrix, int len) {
int i, j;
for (i = 0; i < len; ++i) {
int *row = &matrix[i * len];
for(j = 0; j < len; ++j) {
row[j] = j;
}
}
}
fillMatrix((int *)a, MAX);
fillMatrix((int *)b, MAX);
With that change, everything seems to work fine. I used MAX = 5 and 5 nodes. I prefixed logging statements with the node's rank and added a few more logging statements. Here was the result:
$ mpirun -np 5 ./so_mpi
node 1 of 5
node 4 of 5
node 0 of 5
0: filling matrices
0: matrix B:
0 1 2 3 4
0 1 2 3 4
0 1 2 3 4
0 1 2 3 4
0 1 2 3 4
0: matrix A:
0 1 2 3 4
0 1 2 3 4
0 1 2 3 4
0 1 2 3 4
0 1 2 3 4
0: broadcast of B complete
0: sending 1 rows (5 elements) of A to node 1
0: sending 1 rows (5 elements) of A to node 2
0: sending 1 rows (5 elements) of A to node 3
0: sending 1 rows (5 elements) of A to node 4
0: matrix A:
0 1 2 3 4
0 1 2 3 4
0 1 2 3 4
0 1 2 3 4
0 1 2 3 4
1: broadcast of B complete
1: received portion of matrix
1: matrix A:
0 0 0 0 0
0 1 2 3 4
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
node 2 of 5
2: broadcast of B complete
2: received portion of matrix
2: matrix A:
0 0 0 0 0
0 0 0 0 0
0 1 2 3 4
0 0 0 0 0
0 0 0 0 0
node 3 of 5
3: broadcast of B complete
3: received portion of matrix
3: matrix A:
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 1 2 3 4
0 0 0 0 0
4: broadcast of B complete
4: received portion of matrix
4: matrix A:
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 1 2 3 4

Resources