printing two dimensional array in c - c

I am trying to define a two dimensional array by initially defining elements for 5 x 2 matrix and then I am defining again the elements for 6th row. But when I try to print the elements of this matrix I am getting 0 and 5 for the last value. Tried same by defining elements again for 4th or 6th row but then it is working fine.
#include<math.h>
#include<stdio.h>
main()
{
int arr[ ][2]={{11,12},{21,22},{31,32},{41,42},{51,52}};
int i, j;
arr[5][0]=61; arr[5][1]=62;
for (i=0;i<=5;i++)
{
for (j=0;j<=1;j++)
{
printf ("%d \n", arr[i][j]);
}
}
}

Your initialised array is given exactly enough memory to hold the specified data values. So
int arr[ ][2]={{11,12},{21,22},{31,32},{41,42},{51,52}};
creates the array as int arr[5][2] and then the line
arr[5][0]=61; arr[5][1]=62;
exceeds the array bounds. The maximum index is [4][1] because array indexing is 0 based. If you want to add another element you should specify
int arr[6][2]={{11,12},{21,22},{31,32},{41,42},{51,52}};
and then this line will work.
arr[5][0]=61; arr[5][1]=62;
An alternative would be to use malloc() to allocate memory for the array, and then if you want to add another row you can use realloc(), and this shows how to make a flexible array.
#include <stdio.h>
#include <stdlib.h>
#define COLUMNS 2
#define ROWS 5
typedef int rowtype[COLUMNS];
int main() {
int i, j;
rowtype *array = malloc(ROWS * sizeof(rowtype));
if (array == NULL)
return -1;
for (j=0; j<ROWS; j++)
for (i=0; i<COLUMNS; i++)
array[j][i] = (j+1)*10 + (i+1);
for (j=0; j<ROWS; j++) {
for (i=0; i<COLUMNS; i++)
printf ("%-4d", array[j][i]);
printf ("\n");
}
printf("Add another row\n");
array = realloc(array, (ROWS+1) * sizeof(rowtype));
if (array == NULL)
return -1;
array[ROWS][0] = 61;
array[ROWS][1] = 62;
for (j=0; j<ROWS+1; j++) {
for (i=0; i<COLUMNS; i++)
printf ("%-4d", array[j][i]);
printf ("\n");
}
free(array);
return 0;
}
Program output:
11 12
21 22
31 32
41 42
51 52
Add another row
11 12
21 22
31 32
41 42
51 52
61 62

Related

Printing out each time 2 more elements of an array

How can I print out each line two more elements of an array...?
I can't get it done.
I have this short code, but this part is missing...
#include <stdio.h>
#include <stdlib.h>
char *toChar(int numbers[]);
int main(){
// FILE *fp;
int num;
printf("Number of rows: ");
scanf("%d", &num);
int val[num], value=num;
for(int i=0; i<num; i++){
val[i]=value;
value+=value;
printf("%d ", val[i]);
...
printf("\n");
}
}
return 0;
}
I would like to achieve this... for input = 4.
4 8
12 16 20 24
28 32 36 40 44 48
52 56 60 64 68 72 76 80
And for input 3, expected output is:
3 6
9 12 15 18
21 24 27 30 33 36
Note that the printed value should increase by the same amount as there should be rows (num).
I would make a list of all you need:
You need num rows
You need the number of columns to increase by 2 every row
You need the printed value to increase by num for each output
With that list, make two loops.
One that iterates over the rows
One that iterates over the columns:
#include <stdio.h>
int main() {
printf("Number of rows: ");
int num;
if (scanf("%d", &num) != 1) return 1;
// row starts at 0 and ends at num-1
// columns start with 2 and increases by 2 for every row
for (int row = 0, columns = 2, value = num; row < num; ++row, columns += 2) {
// and value increases by `num` every time it's been printed:
for (int c = 0; c < columns; ++c, value += num) {
printf("%d ", value);
}
putchar('\n');
}
}
Demo
Decided to take a stab at this using java. I feel like recursion here was a bit easier than trying to wrap my head around two for loops.
class Main {
public static void main(String[] args) {
printTwoMore(0, 1, 1, 4);
}
public static void printTwoMore(int prevTimesToPrint, int multiple, int currentRow, int maxRow) {
if (currentRow > maxRow) {
return;
}
int timesToPrint = 2 + prevTimesToPrint;
for (int i = 0; i < timesToPrint; i++) {
System.out.print(4 * multiple + " ");
multiple++;
}
System.out.println("");
currentRow++;
printTwoMore(timesToPrint, multiple, currentRow, maxRow);
}
}

How to iterate through and copy double pointer in C

I've created a two dimensional integer array in C, initialised it with values, and then cast it to an int** (I have to do that because it's for homework).
I've managed to iterate through it and set all of the values to 0. However, when I iterate through it again and print the values it, the output is not all zeros.
Here is a minimum working example:
#include <string.h>
#include <stdio.h>
#define ROWS 3
#define COLS 2
int main(void)
{
/* Create array and convert to double pointer */
int c[ROWS][COLS] = {{1,2},{3,5},{8,13}};
int **ptr = (int **)c;
/* Loop through entire array and print then double each value. */
int *temp[ROWS];
for(int i = 0; i<ROWS; i++){
temp[i] = (int*)(ptr+i);
for(int j = 0; j<COLS; j++){
printf("Before setting: %i\n", temp[i][j]);
temp[i][j] = temp[i][j]*2;
}
}
/* Copy temp back into ptr */
memcpy(ptr, temp, sizeof(ptr));
/* Loop through array and print values */
int *temp2[ROWS];
for(int i = 0; i<ROWS; i++){
temp2[i] = (int*)(ptr+i);
for(int j = 0; j<COLS; j++){
printf("After setting: %i\n", temp2[i][j]);
}
}
}
The issue is that the results are not what I would expect. One time I ran it, this was the output:
Before setting: 1
Before setting: 2
Before setting: 3
Before setting: 5
Before setting: 8
Before setting: 13
After setting: -1193330832
After setting: 32764
After setting: 6
After setting: 10
After setting: 16
After setting: 26
The value 32764 is the same every time the program is run, but the value -1193330832 changes each time (I assume it is the memory address of the array).
The output I was expecting is:
Before setting: 1
Before setting: 2
Before setting: 3
Before setting: 5
Before setting: 8
Before setting: 13
After setting: 1
After setting: 4
After setting: 6
After setting: 10
After setting: 16
After setting: 26
because the values in the first loop have been doubled.
What have I done wrong? Why are the values changing and how should I actually go about fixing this?
(P.S. the homework doesn't involve finding a way to iterate through the double pointer, but I need to be able to do it to complete the actual task)
int **ptr = (int **)c; isn't a valid pointer conversion, since you cannot use a pointer-to-pointer to point at a 2D array. Because it has nothing to do with 2D arrays.
Instead you can use a pointer to a 2D array, int (*)[ROWS][COLS];. The most convenient is however to use a pointer to a 1D array and have it point at the first element of the 2D array:
int (*ptr)[COLS] = &c[0];
...
ptr[i][j] = ...;
Fixed example:
#include <string.h>
#include <stdio.h>
#define ROWS 3
#define COLS 2
int main(void)
{
/* Create array and convert to double pointer */
int c[ROWS][COLS] = {{1,2},{3,5},{8,13}};
int (*ptr)[COLS] = &c[0];
/* Loop through entire array and print then double each value. */
for(int i = 0; i<ROWS; i++){
for(int j = 0; j<COLS; j++){
printf("Before setting: %i\n", ptr[i][j]);
ptr[i][j] = ptr[i][j]*2;
}
}
/* Loop through array and print values */
for(int i = 0; i<ROWS; i++){
for(int j = 0; j<COLS; j++){
printf("After setting: %i\n", ptr[i][j]);
}
}
}
(A matter of style, but your order of ROWS and COLS is a bit weird, it is more common to do int[COLS][ROWS] then for(i=0; i<COLS; i++))

reshape 2D array into 3D array C

Hi I am trying to convert matlab code in C . While doing that I have to reshape a 2d array into 3d array. I tried to write a function which is given below. I took help from here.
#include <stdio.h>
#include <stdlib.h>
#define ZALLOC(item, n, type) if ((item = (type *)calloc((n), sizeof(type))) == NULL) \
fatalx("Unable to allocate %d unit(s) for item\n", n)
int i,j,k,x,y;
static void fatalx(const char *str, size_t n)
{
fprintf(stderr, "%s: %zu\n", str, n);
exit(1);
}
static int ***alloc_3d(int ar[][12],int rows, int cols,int levels)
{
int count = 0;
int ***array_3d;
ZALLOC(array_3d, levels, int **);
for (i = 0; i < levels; i++)
{
int **data;
ZALLOC(data, rows, int *);
array_3d[i] = data;
for (j = 0; j < rows; j++)
{
int *entries;
ZALLOC(entries, cols, int);
array_3d[i][j] = entries;
for (k = 0; k < cols; k++)
{
array_3d[i][j][k] = ar[i][j];
}
}
}
return array_3d;
}
static void print_3d(int ***a3d, int rows, int cols,int levels)
{
for (i = 0; i < levels; i++)
{
printf("%d:\n", i);
for (j = 0; j < rows; j++)
{
printf(" %d: ", j);
for (k = 0; k < cols; k++)
printf(" %3d", a3d[i][j][k]);
putchar('\n');
}
}
}
static void free_3d(int ***a3d, int levels, int rows)
{
for (i = 0; i < levels; i++)
{
for (j = 0; j < rows; j++)
free(a3d[i][j]);
free(a3d[i]);
}
free(a3d);
}
int main(void)
{
int ar[2][12]={
{1,2,3,4,5,6,7,8,9,10,11,12},
{13,14,15,16,17,18,19,20,21,22,23,24}
};
int d1 = 2;
int d2 = 3;
int d3 = 4;
int ***a3d = alloc_3d(ar,d1, d2, d3);
print_3d(a3d, d1, d2, d3);
free_3d(a3d, d3, d2);
return(0);
}
This not only giving me wrong values but also garbage values. Where matlab output for first slice is:
a3d(:,:,1) =
1 2 3
13 14 15
mine one is totally different with
0:
0: 1 1 1
1: 2 2 2
1:
0: 13 13 13
1: 14 14 14
2:
0: 1991011277 1991011277 1991011277
1: 4 4 4
3:
0: 1 1 1
1: 6630248 6630248 6630248
As you can see there is garbage value too. So my indexing is also wrong. Any idea how to properly do that?
Thanks in advance.
Your example does not, in fact, perform a reshaping, inasmuch as it creates a composite object of a completely different type from that of the original array.
A C multidimensional array is an array of arrays (of arrays ...). Among other significant characteristics, all of the elements of such an array are contiguous in memory. You can also construct an array of pointers, and initialize each pointer to point to an array of its own, etc.. Although these kinds of objects are superficially similar in that you can apply the indexing operator to to both in about the same way, it is important to understand that:
The array of pointers requires additional space for the pointers, above and beyond the space to which they point.
Although the pointers in an array of pointers are contiguous in memory, the arrays they point to very well might not be. That often leads to
wasted space if the system's page size does not evenly divide the pointed-to arrays' sizes, and
poorer performance for accessing array elements as a result of poorer locality of reference.
The array of pointers is messier and slower to allocate, because multiple separate calls are required to memory allocation functions.
The array of pointers is messier and slower to free, because all the pointed-to arrays must also be freed, separately.
On the other hand, the array of pointers accommodates "ragged" multi-dimensional pseudo-arrays, were the (pointed to) member arrays are not all the same length.
Here's how your program might look if written using standard C multidimensional arrays (== arrays of arrays):
#include <stdlib.h>
#include <stdio.h>
#define ALLOC(p, n) do { \
if (!((p) = calloc((n), sizeof(*(p))))) { \
fprintf(stderr, "Memory allocation failure\n"); \
exit(1); \
} \
} while (0)
void *reshape_2d_3d(size_t id1, size_t id2, int iar[][id2],
size_t od1, size_t od2, size_t od3) {
// oar is a pointer to a multidimensional array; in this case, it will
// point to the first element of an array of arrays (of arrays).
int (*oar)[od2][od3];
size_t size1 = id1 * id2;
size_t size2 = od1 * od2 * od3;
size_t min_size = (size1 <= size2) ? size1 : size2;
ALLOC(oar, od1);
// A loop nest could be used here, too, but I find this simpler for
// tracking the correspondence of array elements. It also better
// accommodates the case where the reshaped result has different overall
// size from the original.
for (size_t i = 0; i < min_size; i++) {
oar[i / (od2 * od3)][(i / od3) % od2][i % od3] = iar[i / id2][i % id2];
}
return oar;
}
void print_3d(size_t levels, size_t rows, size_t cols, int ar[][rows][cols]) {
for (int i = 0; i < levels; i++) {
printf("%d:\n", i);
for (int j = 0; j < rows; j++) {
printf(" %d: ", j);
for (int k = 0; k < cols; k++) {
printf(" %3d", ar[i][j][k]);
}
putchar('\n');
}
}
}
int main(void) {
int ar[2][12] = {
{1,2,3,4,5,6,7,8,9,10,11,12},
{13,14,15,16,17,18,19,20,21,22,23,24}
};
int d1 = 2, d2 = 3, d3 = 4;
int (*a3d)[d2][d3] = reshape_2d_3d(2, 12, ar, d1, d2, d3);
print_3d(d1, d2, d3, a3d);
// A single, simple free() is all that's needed
free(a3d);
}
Output:
0:
0: 1 2 3 4
1: 5 6 7 8
2: 9 10 11 12
1:
0: 13 14 15 16
1: 17 18 19 20
2: 21 22 23 24
Note that that uses variable-length arrays, but without the usual concern about stack allocation. It therefore requires a conforming C99 compiler, or a conforming C2011 compiler that implements the VLA optional (in that version) feature.
Your way of assigning the numbers to the newly allocated memory is wrong.
static int ***alloc_3d(int ar[][12],int rows, int cols,int levels,int colsize)
{
int count = 0;
int ***array_3d;
ZALLOC(array_3d, levels, int **);
int i1=0,j1=0;
for (i = 0; i < levels; i++)
{ ...
...
for (k = 0; k < cols; k++)
{
array_3d[i][j][k] = ar[i1][j1++];
if( j1 == colsize) i1++,j1=0;
}
}
}
return array_3d;
}
Call like this
int colsize = 12;
int ***a3d = alloc_3d(ar,d1, d2, d3,colsize);
This prints:
0:
0: 1 2 3
1: 4 5 6
1:
0: 7 8 9
1: 10 11 12
2:
0: 13 14 15
1: 16 17 18
3:
0: 19 20 21
1: 22 23 24
A small note - earlier your code had undefined behavior accessing array index out of the bound.

Getting incorrect output when I implement merge sort with threads, can't figure out what's wrong

I've been at this problem for like 3 days and I've combed my entire code to try to figure out why I'm getting incorrect output. The purpose of this program is to do a merge sort using threads. The first part is simply sorting the elements in parallel into however many segments a user inputs. The only inputs tested will be 2, 5, and 10. And the array to be sorted will always be 50 int array of randomly generated numbers.My code works fine when the segments entered (denoted by the variable 'segments' at the top of main) is 2. However, when I change segments to 5 or 10, I don't get a sorted array at the end. I've tried debugging by using print statements (which I've commented out but you can still see) and there seems to be a problem during the first two merge iterations. For some reason the resulting of those merge iterations are not in order, and they contain duplicate numbers that don't exist in duplicate in the original array passed to it. My sorting method and merging methods work fine when I just pass arrays to them, and don't use threads but when I do use threads I get behavior that I can't explain. Below is my program in its entirety, to merge an array of 50 it should do the following:
split the array into 10 segments of 5, and sort each segment.
pass the segments in pairs, in rounds. So round one should pas segment 0-5 in one segment and 5-10 in another, 10-15 and 15-20, 20-25 and 25-30, and so on until it reaches 40-45 and 45-50.
then it will go into round two which does same thing as round one but it passes the segments in pairs of 10. So 0-10 and 10-20, 20-30 and 30-40, then it leaves the last part of 10 untouched
round three passes the segments to merge in pairs of 20: 0-20 and 20-40, then stops.
Finally it should merge the segments 0-40 with 40-50.
My program: (you should mainly focus on my main function, sort is fine, and merge seems fine too, but i've included them anyways just in case)
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <pthread.h>
/**
* Struct to contain an array partition as well as the size of the partition.
* Use struct to pass multiple parameters to pthread_create
*/
struct array_struct{
int *partition;
int size;
};
/**
* Struct that contains two arrays (should be sorted) to merge
* Use struct to pass multiple parameters to pthread_create
*/
struct arrays_to_merge{
int *array1;
int *array2;
int size1;
int size2;
};
//comparison function to use with qsort, sorts in ascending order
int cmpfunc (const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
/**
* Method that takes a struct containing a pointer to the first int in an array
* partition, as well as the partition size. Object must be type void, used with pthread_create
* #param pointer to the partition object. Type void
*/
void *sort(void *object){
struct array_struct *structure;
structure = (struct array_struct *) object;
int *array = structure->partition;
int size = structure->size;
int *i, j = 0;
qsort(array, size, sizeof(int), cmpfunc);
printf("Sorted %d elements.\n", size);
}
void *merge(void * object){
struct arrays_to_merge *arrays_struct;
arrays_struct = (struct arrays_to_merge *) object;
int *array1 = arrays_struct->array1;
int *array2 = arrays_struct->array2;
int size1 = arrays_struct->size1;
int size2 = arrays_struct->size2;
int tempArray[size1 + size2];
int i = 0, j = 0, k = 0, duplicates = 0;
while (i < size1 && j < size2) {
// printf("Merge number : %d Comparing %d and %d\n", mergenumber, array1[i], array2[j]);
if (array1[i] <= array2[j]) {
// printf("Picking %d\n", array1[i]);
tempArray[k] = array1[i];
if (array1[i] == array2[j])
{
duplicates++;
}
i++;
k++;
}else {
// printf("Merge number : %d Picking %d\n", mergenumber, array2[j]);
tempArray[k] = array2[j];
k++;
j++;
}
}
while (i < size1) {
// printf("Merge number : %d left over Picking %d\n", mergenumber, array1[i]);
tempArray[k] = array1[i];
i++;
k++;
}
while (j < size2) {
// printf("Merge number : %d left over Picking %d\n", mergenumber, array2[j]);
tempArray[k] = array2[j];
k++;
j++;
}
array1 = arrays_struct->array1;
for(i = 0; i < size1 + size2; i++){
array1[i] = tempArray[i];
}
printf("Merged %d and %d elements with %d duplicates\n", size1, size2, duplicates);
}
//return an array of size 50 with randomly generated integers
int *randomArray(){
srand(time(NULL));
static int array[50];
int i;
for (i = 0; i < 50; ++i){
array[i] = rand() % 51;
}
return array;
}
int main(int argc, char const *argv[])
{
int segments = 10;//make equal to argv input after testing
pthread_t threads[segments];
int i, *numbers; //iterator i, and pointer to int array 'numbers'
numbers = randomArray(); //return an array of random ints and store in 'numbers'
struct array_struct array[segments];
for(i = 0; i < segments; i++){
int *partition = numbers + (i * (50/segments));//obtain the first index of partition
array[i].partition = partition;
array[i].size = 50/segments;
pthread_create(&threads[i], NULL, sort, (void *) &array[i]);
}
for(i = 0; i < segments; i++){
pthread_join(threads[i], NULL);
}
int count = segments;
struct arrays_to_merge arrays[segments];
int j;
int size = 50/ segments;
while(count > 1){
for(i = 0, j = 0; i < count-1; j++, i += 2){
int *partition = numbers + (i * (size));
int *partition2 = numbers + (i+1 * (size));
arrays[j].array1 = partition;
arrays[j].array2 = partition2;
arrays[j].size1 = size;
arrays[j].size2 = size;
pthread_create(&threads[j], NULL, merge, (void *) &arrays[j]);
}
for(i = 0; i < j; i++){
pthread_join(threads[i], NULL);
}
size = size * 2;
count = count/2;
}
if(segments != 2){//for segments = 2, no need for his
int *partition = numbers;
int *partition2 = numbers + (size);
arrays[0].array1 = partition;
arrays[0].array2 = partition2;
arrays[0].size1 = size;
arrays[0].size2 = 50 - size;
pthread_create(&threads[0], NULL, merge, (void *) &arrays[0]);
pthread_join(threads[0], NULL);
}
for(i = 0; i < 50; i++){
printf("%d\n", numbers[i]);
}
pthread_exit(NULL);
return 0;
}
this is my output:
Sorted 5 elements.
Sorted 5 elements.
Sorted 5 elements.
Sorted 5 elements.
Sorted 5 elements.
Sorted 5 elements.
Sorted 5 elements.
Sorted 5 elements.
Sorted 5 elements.
Sorted 5 elements.
Merged 5 and 5 elements with 0 duplicates
Merged 5 and 5 elements with 0 duplicates
Merged 5 and 5 elements with 0 duplicates
Merged 5 and 5 elements with 0 duplicates
Merged 5 and 5 elements with 0 duplicates
Merged 10 and 10 elements with 3 duplicates
Merged 10 and 10 elements with 1 duplicates
Merged 20 and 20 elements with 7 duplicates
Merged 40 and 10 elements with 17 duplicates
0
6
9
11
12
13
13
14
15
17
19
23
25
25
25
26
26
28
28
28
28
30
32
32
32
34
39
41
41
44
44
44
44
44
50
50
9
15
50
9
15
19
26
50
50
9
15
11
14
50
Sorry for the long wall of text, I've tried resolving this on my own and after countless hairs pulled I can't figure it out. Please help me figure out what I'm doing wrong. I think my problem lies in either the way I'm joining threads, or my merge function but since I cant be sure, i just included the whole thing.
It took a while but finally I got there :)
The problem is with this line:
int *partition2 = numbers + (i+1 * (size));
which is equivalent to (due to operator precedence).
int *partition2 = numbers + (i + size);
and is not what you want.
It should be:
int *partition2 = numbers + ((i+1) * (size));
Notice the additional brackets. Without which, the partition2 index is calculated incorrectly. Hence, merging with different parts of the array.

Floyd-Warshall algorithm not finding length of shortest paths correctly

This is probably a bad question to ask on SO since my rep is so low, but I have been looking through other solutions for hours, and my code seems nearly identical to the working solutions that I've come across. Please do not ignore the question based on low rep.
The output matrix, d[][] contains the (incorrect) lengths of the shortest paths between a given pair of vertices. The solution provided in the networkx library for Python has been used.
As an excerpt, the results for n=20 have been provided. I'm not printing out the paths greater than infinity (i.e. 99999), since there is overflow.
This is what the graph looks like:
My Floyd-Warshall algorithm implementation (C)
20 0 2
20 1 6
20 2 9
20 3 9
20 4 8
20 5 10
20 7 2
20 8 7
20 9 10
20 11 5
20 12 2
20 13 7
20 14 6
20 15 17
20 17 4
20 18 5
Networkx solution to Floyd-Warshall algorithm (Python)
20 0 2
20 1 5
20 2 4
20 3 4
20 4 3
20 5 7
20 7 2
20 8 2
20 9 4
20 11 4
20 12 2
20 13 6
20 14 5
20 15 4
20 17 3
20 18 4
20 20 0
Implementation:
#include <time.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#define INF 9999
#define min(a,b) (a>b)?b:a;
int n;
/*
* Method signatures
*/
void shortestPath(int matrix[][n]);
int main(){
char buf[16], c;
int i, j, weight, ret;
/* Open file handler for file containing test data */
FILE *file = fopen("eg2.txt", "r");
if(file==NULL){
puts("I/O error: cannot read input file");
fclose(file);
exit(1);
}
/* Get number of vertices in file */
fscanf(file, "%d", &n);
/* Initialise matrix of n*3 elements */
int matrix[n][n];
memset(matrix, INF, n*n*sizeof(int));
while((ret = fscanf(file, "%d %d %d", &i, &j, &weight)) != EOF) {
if(ret == 3){
matrix[i][j]=weight;
} else {
printf("ERROR: retrieved %d values (expecting 3)\n", ret);
break;
}
}
fclose(file);
/* Output matrix */
for(i=0; i<n; i++){
matrix[i][i]=0;
for(j=0; j<n; j++){
printf("%d ", matrix[i][j]);
}
printf("\n");
}
shortestPath(matrix);
}
/*
* Implementation of the Floyd-Warshall path finding algorithm
*/
void shortestPath(int matrix[][n]){
int d[n][n], k, i, j;
/* Copy values from matrix[][] to d[][] */
for(i=0; i<n; i++){
for(j=0; j<n; j++){
d[i][j] = matrix[i][j];
}
}
for(k=0; k<n; k++){
for(i=0; i<n; i++){
for(j=0; j<n; j++){
if (d[i][k] + d[k][j] < d[i][j]){
d[i][j] = d[i][k] + d[k][j];
}
}
}
}
for(i=0; i<n; i++){
for(j=0; j<n; j++){
if((d[i][j]!=0)&&(d[i][j]<INF)){
printf("%d\t%d\t%d\n", i, j, d[i][j]);
}
}
}
}
Test client (Python)
#!/usr/bin/python2.7
try:
import matplotlib.pyplot as plt
from collections import defaultdict
import networkx as nx
import numpy as np
except:
raise
nodes = defaultdict(dict)
with open('eg2.txt', 'r') as infile:
for line in infile.readlines()[1:]:
line = map(int, line.split())
src = line[0]
dst = line[1]
weight = line[2]
nodes[src][dst]=weight
G = nx.Graph()
for i in nodes:
for j in nodes[i]:
G.add_edge(i, j, weight=nodes[i][j])
rs = nx.floyd_warshall(G)
for i in rs:
for j in rs[i]:
print "%d\t%d\t%d" % (i, j, rs[i][j])
pos = nx.shell_layout(G)
nx.draw(G, pos, node_size=500, node_color='orange', edge_color='blue', width=1)
plt.axis('off')
plt.show()
Don't use dynamically sized arrays (e.g. non-constant n in the array size), they may not work the way you think. One simple way to fix your code:
#define MAXN 100
int n;
...
int matrix[MAXN][MAXN];
scanf("%d", &n);
if (n < 1 || n > MAXN) abort();
...
void shortestPath(int matrix[][MAXN]) {
Please recompile your code with all warnings enabled (e.g. gcc -W -Wall -Wextra -ansi), fix all the warnings, and indicate in the question that your code compiles without emitting any warning.
Here is a complete solution for you. I used #pts's suggestion of using a fixed array, and the suggestion from the comments of initializing the array explicitly with a pair of nested loops. I also took some liberties with the way the algorithm works - for example, with the option to have either directed or undirected graphs - and show how you can include some intermediate outputs to help in the debugging.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define INF 9999
#define MIN(a,b)((a)<(b))?(a):(b)
// uncomment the next line to make processing symmetrical
// i.e. undirected edges
// #define SYM
#define NMAX 20
int n;
void shortestPath(int m[NMAX][NMAX]);
void printMatrix(int m[NMAX][NMAX]);
// implementation of floyd-warshall algorithm
// with minimal error checking
// input file = series of nodes on graph in form
// start, end, length
// algorithm attempts to find shortest path between any connected nodes
// by repeatedly looking for an intermediate node that shortens the current distance
// graphs are directional - 3 4 5 does not imply 4 3 5
// this can be changed by uncommenting the #define SYM line above
// also, hard coded to have no more than 20 nodes - defined with NMAX above
// path to input file is hard coded as "eg2.txt"
int main(void) {
int i, j, weight, ret;
// open input file:
FILE *fp = fopen("eg2.txt", "r");
if(fp == NULL) {
printf("cannot read input file\n");
exit(1);
}
// read number of nodes in the graph:
fscanf(fp, "%d", &n);
if(n > NMAX) {
printf("input too large\n");
fclose(fp);
exit(1);
}
printf("n is %d\n", n);
// generate matrix:
int matrix[NMAX][NMAX];
for(i=0; i<NMAX;i++)
for(j=0; j<NMAX; j++)
matrix[i][j] = INF;
while( (ret = fscanf(fp, "%d %d %d", &i, &j, &weight)) != EOF) {
if(ret == 3) {
matrix[i][j] = weight;
#ifdef SYM
matrix[j][i] = weight;
#endif
}
else printf("error reading input\n");
}
fclose(fp);
printMatrix(matrix);
shortestPath(matrix);
printMatrix(matrix);
}
void printMatrix(int m[NMAX][NMAX]) {
int i, j;
for(i=0; i<n; i++) {
for(j=0; j<n; j++) {
if(m[i][j]==INF) printf(" - "); else printf("%3d ", m[i][j]);
}
printf("\n");
}
}
void shortestPath(int d[NMAX][NMAX]) {
int i, j, k, temp;
// no need to make a copy of the matrix: operate on the original
for(k=0; k<n; k++) {
for(i=0; i<n-1; i++) {
for(j=0; j<n; j++) {
if(i==j) continue; // don't look for a path to yourself...
if(d[i][k] == INF || d[k][j]==INF) continue; // no path if either edge does not exist
if((temp = d[i][k] + d[k][j]) < d[i][j]) {
d[i][j] = temp;
#ifdef SYM
d[j][i] = temp;
#endif
printf("from %d to %d is shorter via %d: %d + %d is %d\n", i, j, k, d[i][k], d[k][j], temp);
}
}
}
}
for(i=0; i<n; i++) {
for(j=0; j<n; j++) {
if(d[i][j] < INF) printf("%2d %2d %3d\n", i, j, d[i][j]);
}
}
}
With the following input file:
5
1 2 3
2 4 2
1 4 8
0 3 7
3 1 2
1 4 2
1 3 1
0 1 1
I got as output:
n is 5
- 1 - 7 -
- - 3 1 2
- - - - 2
- 2 - - -
- - - - -
from 0 to 2 is shorter via 1: 1 + 3 is 4
from 0 to 3 is shorter via 1: 1 + 1 is 2
from 0 to 4 is shorter via 1: 1 + 2 is 3
from 3 to 2 is shorter via 1: 2 + 3 is 5
from 3 to 4 is shorter via 1: 2 + 2 is 4
0 1 1
0 2 4
0 3 2
0 4 3
1 2 3
1 3 1
1 4 2
2 4 2
3 1 2
3 2 5
3 4 4
- 1 4 2 3
- - 3 1 2
- - - - 2
- 2 5 - 4
- - - - -
Oddly enough, when I ran your code (as posted above) it gave me the same solution - although the output for the first part made it very clear that the memset wasn't working as you expected:
0 1 252645135 7 252645135
252645135 0 3 1 2
252645135 252645135 0 252645135 2
252645135 2 252645135 0 252645135
252645135 252645135 252645135 252645135 0
0 1 1
0 2 4
0 3 2
0 4 3
1 2 3
1 3 1
1 4 2
2 4 2
3 1 2
3 2 5
3 4 4
In fact, the number that is being written to the matrix with the memset operation is 0x0F0F0F0F, which is 252645135 in decimal. You can understand why this is so by looking at the syntax of memset:
void *memset(void *str, int c, size_t n)
Parameters
str -- This is pointer to the block of memory to fill.
c -- This is the value to be set. The value is passed as an int, but the function fills the block of memory using the unsigned char conversion of this value.
n -- This is the number of bytes to be set to the value.
and combining with the hexadecimal representation of 9999, which is
0x270F
The "unsigned char conversion" of an int is that number modulo 256, or the least significant byte. In this case, the least significant byte is 0x0F and that is the value that gets written (repeatedly) to every byte in the block - hence the value 0x0F0F0F0F (on my machine, an int is four bytes long).
Afterword
Finally - if you want to use "any size of array", you can add the following couple of functions to your program - and replace the function signatures as indicated. This is a "tricky" way to create a two D array of variable size in C - essentially, when C comes across a pointer of the type int** it will dereference twice. By making this pointer-to-a-pointer point to a block of pointers to the block of memory, you create in effect a 2D array that the compiler can understand.
int **make2D(int r, int c) {
int ii, **M;
M = malloc(r * sizeof(int*) );
M[0] = malloc( r * c * sizeof(int) );
for(ii=1; ii<r; ii++) M[ii] = M[0] + ii * c * sizeof(int);
return M;
}
void free2D(int** M) {
free(M[0]);
free(M);
}
Now you generate your matrix with
int **matrix;
matrix = make2D(n, n);
and you change the function signatures to
void shortestPath(int **m);
void printMatrix(int **m);
And call them with
shortestPath(matrix); // etc
To make everything work properly you have to make a few other adjustments in your code (example: you should not try to assign INF to all elements of a NMAX by NMAX array when you allocated less memory than that). You can try to figure this out for yourself - but just in case, here is the complete code. One other change I made - I got rid of n as a global variable and made it local to main (and passed it to the various routines that needed it). This is usually a good practice - it's all too easy to mix things up with globals, so use them only when you really have no choice.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define INF 9999
#define MIN(a,b)((a)<(b))?(a):(b)
// uncomment the next line to make processing symmetrical
// i.e. undirected edges
// #define SYM
void shortestPath(int **m, int n);
void printMatrix(int **m, int n);
// create 2D matrix of arbitrary (variable) size
// using standard C:
int **make2D(int r, int c) {
int ii, **M;
M = malloc(r * sizeof(int*) );
M[0] = malloc( r * c * sizeof(int) );
for(ii=1; ii<r; ii++) M[ii] = M[0] + ii * c * sizeof(int);
return M;
}
void free2D(int** M) {
free(M[0]);
free(M);
}
// implementation of floyd-warshall algorithm
// with minimal error checking
// input file = series of nodes on graph in form
// start, end, length
// algorithm attempts to find shortest path between any connected nodes
// by repeatedly looking for an intermediate node that shortens the current distance
// graphs are directional - 3 4 5 does not imply 4 3 5
// this can be changed by uncommenting the #define SYM line above
// also, hard coded to have no more than 20 nodes - defined with NMAX above
// path to input file is hard coded as "eg2.txt"
int main(void) {
int i, j, n, weight, ret;
// open input file:
FILE *fp = fopen("eg2.txt", "r");
if(fp == NULL) {
printf("cannot read input file\n");
exit(1);
}
// read number of nodes in the graph:
fscanf(fp, "%d", &n);
printf("n is %d\n", n);
// generate matrix:
int **matrix;
// allocate memory:
matrix = make2D(n, n);
// fill all elements with INF:
for(i=0; i<n;i++)
for(j=0; j<n; j++)
matrix[i][j] = INF;
// read the input file:
while( (ret = fscanf(fp, "%d %d %d", &i, &j, &weight)) != EOF) {
if(ret == 3) {
matrix[i][j] = weight;
#ifdef SYM
// if undirected edges, put in both paths:
matrix[j][i] = weight;
#endif
}
else printf("error reading input\n");
}
fclose(fp);
printMatrix(matrix, n);
shortestPath(matrix, n);
printMatrix(matrix, n);
}
void printMatrix(int **m, int n) {
int i, j;
for(i=0; i<n; i++) {
for(j=0; j<n; j++) {
if(m[i][j]==INF) printf(" - "); else printf("%3d ", m[i][j]);
}
printf("\n");
}
}
void shortestPath(int **d, int n) {
int i, j, k, temp;
// no need to make a copy of the matrix: operate on the original
for(k=0; k<n; k++) {
for(i=0; i<n-1; i++) {
for(j=0; j<n; j++) {
if(i==j) continue; // don't look for a path to yourself...
if(d[i][k] == INF || d[k][j]==INF) continue; // no path if either edge does not exist
if((temp = d[i][k] + d[k][j]) < d[i][j]) {
d[i][j] = temp;
#ifdef SYM
d[j][i] = temp;
#endif
printf("from %d to %d is shorter via %d: %d + %d is %d\n", i, j, k, d[i][k], d[k][j], temp);
}
}
}
}
for(i=0; i<n; i++) {
for(j=0; j<n; j++) {
if(d[i][j] < INF) printf("%2d %2d %3d\n", i, j, d[i][j]);
}
}
}

Resources