Passing 2D array by reference to function - arrays

I am trying to add two matrices using 2D arrays in C. Here I am passing the array name as a parameter, which I think is pass by reference. However, I cannot add the arrays. Something is fishy in the add function, I cannot add the arrays.
I even tried to pass the parameter using address of Operator, however arrays are pointer themselves so it got error. I tried passing with the name of array. I am stuck
#include<stdio.h>
void input(int*,int*);
void add(int*,int*,int*);
void display(int*);
int main()
{
int a[3][3],b[3][3],sum[3][3];
input(a,b);
add(a,b,sum);
display(sum);
return 0;
}
void input(int*a,int*b)
{
for(int i = 0;i<3;i++)
{
for(int j =0;j<3;j++)
{
printf("Enter the element at a[%d][%d]",i+1,j+1);
scanf("%d",((a+i)+j));
}
}
for(int i = 0;i<3;i++)
{
for(int j =0;j<3;j++)
{
printf("Enter the element at b[%d][%d]",i+1,j+1);
scanf("%d",((b+i)+j));
}
}
}
void add(int* a,int*b,int*sum)
{
for(int i =0;i<3;i++)
{
for(int j=0;j<3;j++)
{
*(sum[i]+j) = *(a[i]+j) + *(b[i]+j);//error at this line
}
}
}
void display(int* sum)
{
printf("The sum is:\n");
for(int i =0;i<3;i++)
{
for(int j =0;j<3;j++)
{
printf("%d ",(sum[i]+j));
}
printf("\n");
}
}
I got the following error
operand of '*' must be a pointer
However my operand is readily a pointer.

The problem is that the methods:
void input(int*, int*);
void add(int*, int*, int*);
void display(int*);
expected a pointer, however you are passing to them 2D arrays (statically allocated), namely int a[3][3], b[3][3], sum[3][3];. Therefore, as already pointed out in the comments, those 2D arrays will be converted to 'int (*)[3]'. Consequently, you need to adapt the signature of your methods to:
void input(int [][3], int [][3]);
void add(int [][3], int [][3], int [][3]);
void display(int [][3]);
and
void input(int a[][3], int b[][3]){
// the code
}
void add(int a [][3], int b [][3], int sum [][3]){
// the code
}
void display(int sum [][3]){
// the code
}
Alternatively, if you want to keep the int* as parameter then what you can do is to allocate the matrix as a single array and adapt your code accordingly

Here I am passing the array name as a parameter,which i think is pass
by refernece.However I cannot add the arrays.Something is fishy in the
add function,i cannot add the arrays
You can use int* or use int[][], but you need to write the program as required by each case. I will show you an example of both cases.
about your program
do not use void. It is in general a waste, sometimes an error. Return something.
write generically. Compare:
void display(int* sum)
{
printf("The sum is:\n");
for(int i =0;i<3;i++)
{
for(int j =0;j<3;j++)
{
printf("%d ",(sum[i]+j));
}
printf("\n");
}
}
with
void display_a(int s[][3], int l, const char* msg)
{
if( *msg != 0) printf("%s\n",msg);
for(int i =0;i<l;i++)
{
for(int j =0;j<3;j++)
{
printf("%d ", s[i][j]);
}
printf("\n");
}
printf("\n");
return;
};
In the second case you can use the same function to display ANY array s and also write a simple title. Note that in C you can omit all but the last dimension in the vector. In fact C does not have multidimensional array as e.g. FORTRAN has. And passing the number of lines and the message as parameters you have much more than just using as you wrote.
NEVER write
printf("Enter the element at a[%d][%d]",i+1,j+1);
scanf("%d",((a+i)+j));
always test the return of scanf(). scanf() is not meant to read from the keyboard. Use at least one space in every prompt. Is is far more confortable to the user.
Use constants to test your program. Avoid reading for the user as it will waste much time on testing.
An example
output
Using arrays
Matriz A at [1][1] 1
Matriz A at [1][2] 2
Matriz A at [1][3] 3
Matriz A at [2][1] 4
Matriz A at [2][2] 5
Matriz A at [2][3] 6
Matriz B at [1][1] 6
Matriz B at [1][2] 5
Matriz B at [1][3] 4
Matriz B at [2][1] 3
Matriz B at [2][2] 2
Matriz B at [2][3] 1
The 1st matrix:
1 2 3
4 5 6
The 2nd matrix:
6 5 4
3 2 1
The sum (using arrays) is:
7 7 7
7 7 7
Using pointers
Matriz A at [1][1] 2
Matriz A at [1][2] 3
Matriz A at [1][3] 4
Matriz A at [2][1] 5
Matriz A at [2][2] 6
Matriz A at [2][3] 7
Matriz B at [1][1] 7
Matriz B at [1][2] 6
Matriz B at [1][3] 5
Matriz B at [2][1] 4
Matriz B at [2][2] 3
Matriz B at [2][3] 2
The 1st matrix:
2 3 5
5 6 7
The 2nd matrix:
7 6 4
4 3 2
The sum (using pointers) is:
9 9 9
9 9 9
Using t1 t2
The t1 matrix:
1 2 3
4 5 6
7 8 9
The t2 matrix:
9 8 7
6 5 4
3 2 1
t1 + t2 (using pointers) is:
10 10 10
10 10 10
10 10 10
the code
this code uses all that I tried to explain, I believe. Pay attention to the way you write the code when using the pointers: you just use the address and displacement.No brackets are needed.
#include<stdio.h>
void add_a(int[][3],int[][3],int[][3],int);
void display_a(int[][3],int,const char*);
int input_a(int[][3], int, const char*);
void add_p(int*,int*,int*,int);
void display_p(int*,int,const char*);
int input_p(int*, int, const char*);
int main(void)
{
int t1[][3] =
{
{ 1,2,3 },
{ 4,5,6 },
{ 7,8,9 }
};
int t2[][3] =
{
{ 9,8,7 },
{ 6,5,4 },
{ 3,2,1 }
};
int a[3][3];
int b[3][3];
int sum[3][3];
printf("Using arrays\n\n");
input_a(a,2,"Matriz A");
input_a(b,2,"Matriz B");
display_a(a, 2, "The 1st matrix:");
display_a(b, 2, "The 2nd matrix:");
add_a( a,b,sum, 2 );
display_a(sum, 2, "The sum (using arrays) is:");
printf("Using pointers\n\n");
input_p((int*) a,2,"Matriz A");
input_p((int*) b,2,"Matriz B");
display_p( (int*) a, 2, "The 1st matrix:");
display_p( (int*) b, 2, "The 2nd matrix:");
add_p( (int*) a, (int*) b, (int*) sum, 2 );
display_p( (int*) sum, 2, "The sum (using pointers) is:");
printf("\nUsing t1 t2 \n\n");
display_p( (int*) t1, 3, "The t1 matrix:");
display_p( (int*) t2, 3, "The t2 matrix:");
add_p( (int*) t1, (int*) t2, (int*) sum, 3 );
display_p( (int*) sum, 3, "t1 + t2 (using pointers) is:");
return 0;
};
void add_a(
int a[][3],
int b[][3],
int sum[][3],
int l // lines
)
{
for(int i =0;i<l;i++)
for(int j=0;j<3;j++)
sum[i][j] = a[i][j] + b[i][j];
return;
};
void display_a(int s[][3], int l, const char* msg)
{
if( *msg != 0) printf("%s\n",msg);
for(int i =0;i<l;i++)
{
for(int j =0;j<3;j++)
{
printf("%d ", s[i][j]);
}
printf("\n");
}
printf("\n");
return;
};
int input_a(int a[][3], int l, const char* msg )
{
for(int i = 0;i<l;i++)
{
for(int j =0;j<3;j++)
{
printf("%s at [%d][%d] ", msg, i+1,j+1);
int res = scanf("%d",&a[i][j]);
if ( res != 1 ) return -1; // read nothing
}
};
return 0;
};
void add_p( int*a, int* b, int* sum, int l )
{
for(int i =0;i<l;i++)
for(int j=0;j<3;j++)
*(sum + i*l + j) = *(a + i*l + j) + *(b + i*l + j);
return;
};
void display_p(int* s, int l, const char* msg)
{
if( *msg != 0) printf("%s\n",msg);
for(int i =0;i<l;i++)
{
for(int j =0;j<3;j++)
printf("%d ", *( s + i*l + j) );
printf("\n");
};
printf("\n");
return;
};
int input_p(int* a, int l, const char* msg )
{
for(int i = 0;i<l;i++)
{
for(int j =0;j<3;j++)
{
printf("%s at [%d][%d] ", msg, i+1,j+1);
int res = scanf("%d", (a + i*l + j) );
if ( res != 1 ) return -1; // read nothing
}
};
return 0;
};

Related

How to pass pointer of arrays to functions

With my programm I try to change the order of numbers in the int array. To the first function, I just passed both arrays and printed the array called arraytemp with the changed order. After that I printed in the main function the same array, just to see if the array was filled too. I havented used any pointers in the first function - how did the array got filled? Does the arrays adress get passed to functions anyway?
Then I wanted to pass arrays with the same content to the second function, but this time I used pointers. I have no clue, how to get the same result printed, because I get a stack smashing error. I am kinda comfused with '*' and '&'. So, how should I pass these arrays when using pointers?
#include <stdio.h>
void switchnum (int arraytemp[6], int array[], int laenge) {
printf("\n\nAfter (in function 1):\n");
for(int i = 0 ; i<laenge ; i++) {
arraytemp[i] = array[laenge-1-i];
printf("%d ", arraytemp[i]);
}
return 0;
}
void switchnum2 (int *arraytemp2[6], int array2[], int laenge2) {
printf("\nAfter (in function2):\n");
for(int j = 0 ; j<laenge2 ; j++) {
arraytemp2[j] = array2[laenge2-1-j];
printf("%d ", arraytemp2[j]);
}
return 0;
}
int main() {
int array[] = {4,8,1,3,0,9};
int arraytemp[6];
printf("Before (main):\n");
for(int i = 0 ; i<6 ; i++) {
printf("%d ", array[i]);
}
switchnum(arraytemp, array, 6);
printf("\nAfter (in main):\n");
for(int i = 0 ; i<6 ; i++) {
printf("%d ", arraytemp[i]);
}
int array2[] = {4,8,1,3,0,9};
int arraytemp2[6];
switchnum2(arraytemp2, array2, 6);
return 0;
}
The compiler adjusts a parameter having an array type to pointer to the array element type.
So this function declaration
void switchnum (int arraytemp[6], int array[], int laenge);
is equivalent to the following declaration
void switchnum (int arraytemp[], int array[], int laenge);
and the same way is equivalent to the following declaration
void switchnum (int *arraytemp, int *array, int laenge);
As for this function declaration
void switchnum2 (int *arraytemp2[6], int array2[], int laenge2);
then it is adjusted by the compiler to the declaration
void switchnum2 (int **arraytemp2, int *array2, int laenge2);
So the used argument expression and the function parameter have incompatible pointer types.
Pay attention to that in this call
switchnum(arraytemp, array, 6);
the both arrays are converted to pointers to their first elements of the type int *.
In fact this call is equivalent to
switchnum( &arraytemp[0], &array[0], 6);
How to pass pointer of arrays to functions
In this case you are trying to pass an array of pointers to a function and not a pointer of arrays:
void switchnum2(
int* arraytemp2[6], int array2[], int laenge2)
Maybe it helps to see the output of this example program, as it shows the output of many of your cases
Example
#include <stdio.h>
void test_arr(int*[6]);
int main(void)
{
int array[] = {4, 8, 1, 3, 0, 9};
int* pArr[6] = {0}; // 6 pointers to int
printf("original vector in main(): ");
for (int i = 0; i < 6; i += 1) printf("%d ", array[i]);
printf("\n");
for (int i = 0; i < 6; i++) pArr[i] = &array[i];
test_arr(pArr);
printf("\nIn main() &array[0] = %p\n", &array[0]);
return 0;
}
void test_arr(int* pInt[6])
{
printf("In test_array(): ");
for (int i = 0; i < 6; i += 1)
printf("%d ", *pInt[i]);
printf("\n");
int* myP = *pInt;
printf("*pInt\tpoints to value %d\n", *myP);
myP = pInt[0];
printf("pInt[0]\tpoints to value %d\n", *myP);
int x = *pInt[0];
printf("*pInt[0] = %d\n", x);
printf("\ntest_array() &pInt[0] = %X\n", pInt[0]);
return;
}
output
original vector in main(): 4 8 1 3 0 9
In test_array(): 4 8 1 3 0 9
*pInt points to value 4
pInt[0] points to value 4
*pInt[0] = 4
test_array() &pInt[0] = 197BFB00
In main() &array[0] = 000000CF197BFB00
Your program with some changes in the functions
I changed some lines in your code to get the expected result
#include <stdio.h>
void switch1(const int[],int[],const int);
void switch2(const int[],int*[],const int);
void show_array(const int[6],const char*);
int main(void)
{
int arr_out[] = {0,0,0,0,0,0};
show_array(arr_out, "arr_out in main()");
// call 1st function
printf("switch1() uses int[] as output\n");
switch1((int[6]){6, 5, 4, 3, 2, 1}, arr_out, 6);
show_array(arr_out, "arr_out using 6..1 array as input and 1st function");
// for 2nd function we need an array of pointers
int* pArr[6] = {0}; // 6 pointers to int
for (int i = 0; i < 6; i++) pArr[i] = &arr_out[i];
printf("switch2() uses int*[] as output\n");
switch2((int[6]){1, 2, 3, 4, 5, 6}, pArr, 6);
show_array(arr_out, "arr_out using 1..6 array as input and 2nd function");
return 0;
}
void switch1(const int in[], int out[], const int laenge)
{
for (int i = 0; i < laenge; i++)
out[i] = in[laenge - 1 - i];
}
void switch2(const int in[], int* out[], const int laenge)
{
for (int i = 0; i < laenge; i++)
*out[i] = in[laenge - 1 - i];
}
void show_array(const int array[6], const char* msg)
{
printf("%s:\t", msg);
for (int i = 0; i < 6; i++) printf("%d ", array[i]);
printf("\n");
}
output of the modified code
arr_out in main(): 0 0 0 0 0 0
switch1() uses int[] as output
arr_out using 6..1 array as input and 1st function: 1 2 3 4 5 6
switch2() uses int*[] as output
arr_out using 1..6 array as input and 2nd function: 6 5 4 3 2 1
about the changes
void show_array(const int array[6], const char* msg)
{
printf("%s:\t", msg);
for (int i = 0; i < 6; i++) printf("%d ", array[i]);
printf("\n");
}
This function is a helper to show the array contents and accepts a title. Very convenient here
the 2 functions has no output (printf() calls)
parameters are declared const so we can build the vector at the function call
I am using shorter names and changed the order of arguments to input and then output
void switch1(const int in[], int out[], const int laenge)
{
for (int i = 0; i < laenge; i++)
out[i] = in[laenge - 1 - i];
}
void switch2(const int in[], int* out[], const int laenge)
{
for (int i = 0; i < laenge; i++)
*out[i] = in[laenge - 1 - i];
}
Here you see the difference between the 2 functions: a single asterisk.
But in order of using the second function you need to build the vector of pointers as here
// call 1st function
printf("switch1() uses int[] as output\n");
switch1((int[6]){6, 5, 4, 3, 2, 1}, arr_out, 6);
show_array(arr_out, "arr_out using 6..1 array as input and 1st function");
// for 2nd function we need an array of pointers
int* pArr[6] = {0}; // 6 pointers to int
for (int i = 0; i < 6; i++) pArr[i] = &arr_out[i];
printf("switch2() uses int*[] as output\n");
switch2((int[6]){1, 2, 3, 4, 5, 6}, pArr, 6);
show_array(arr_out, "arr_out using 1..6 array as input and 2nd function");

Snake sort a 2D array with pointers

I'm bad at C pointers, I'm not sure how should I sort the whole array, the code below sorted the array row-wise only, with a warning "assignment discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]". This code sure works in Windows, not sure for other OSes. I am supposed to create a function called snake with 2D const int pointer array, and its size, m as inputs. I am not allowed to move or swap the contents within the array to be scanned, also the whole main function is not allowed to be edited. For example, the input for the whole program is
3
9 8 7
5 4 6
3 2 1
The correct output should be
1 2 3
6 5 4
7 8 9
Instead, I got this
7 8 9
4 5 6
1 2 3
And here is my code. There is a commented section in snake() because the assert function will fail if I uncomment it. I was trying to reverse the even rows (but the index starts from 0, so you can say odd rows also) after sorting.
#include <stdio.h>
#include <assert.h>
void snake(const int *ptr_array[100][100], int m){
int* p =NULL;
int temp;
for(int y=0;y<m;y++){
for(int k=0;k<m-1;k++){
for(int g=0;g<m-k-1;g++){
if(*ptr_array[y][g]>*ptr_array[y][g+1]){
p=(ptr_array[y][g]);
(ptr_array[y][g])=(ptr_array[y][g+1]);
(ptr_array[y][g+1]) = p;
}
}
}
}
// for(int h=1;h<m;h+=2){
// for(int g=0;g<m/2;g++){
// p = (ptr_array[h][m-g]);
// (ptr_array[h][m-g]) = (ptr_array[h][g]);
// (ptr_array[h][g]) = p;
// }
// }
}
int main()
{
int array[100][100], check[100][100];
const int *ptr_array[100][100];
int i, j, m;
scanf("%d", &m);
for (i = 0; i < m; i++){
for (j = 0; j < m; j++) {
ptr_array[i][j] = &(array[i][j]);
scanf("%d", &(array[i][j]));
check[i][j] = array[i][j];
}
}
snake(ptr_array, m);
for (i = 0; i < m; i++) {
for (j = 0; j < m; j++) {
assert(check[i][j] == array[i][j]);
assert((ptr_array[i][j] >= &array[0][0]) && (ptr_array[i][j] <= &array[99][99]));
printf("%d ", *(ptr_array[i][j]));
}
printf("\n");
}
return 0;
}
#include <stdio.h>
void snake(const int *ptr_array[100][100], int m){
int* p =NULL;
int* w=NULL;
int temp,l;
for(int y=0;y<m;y++){
for(int k=0;k<m;k++){
p = ptr_array[y][k];
l = k+1;
for(int g=y;g<m;g++){
while(l<m){
if(*p>*ptr_array[g][l]){
p=(ptr_array[g][l]);
(ptr_array[g][l])=(ptr_array[y][k]);
(ptr_array[y][k]) = p;
}
l++;
}
l=0;
}
}
}
for(int h=1;h<m;h+=2){
for(int g=0;g<=(m-1)/2;g++){
w = (ptr_array[h][m-1-g]);
(ptr_array[h][m-1-g]) = (ptr_array[h][g]);
(ptr_array[h][g]) = w;
}
}
}

How to modify an array inside a function in C

Let's consider the following example :
#include <stdio.h>
void change_byte(int *byte);
int main()
{
int byte = 0;
change_byte(&byte);
printf("Byte : %d \r\n", byte);
}
void change_byte(int *byte)
{
*byte= 5;
}
I am simply changing the value of an integer inside a function by passing the integer as a pointer to the function. It yields :
Byte : 5
Everything's fine.
I want to generalize the function to modify an array of integer instead of an integer. Here is the code :
#include <stdio.h>
#define SIZE_ARRAY 10
void change_array(int *array, int size);
int main()
{
int array[SIZE_ARRAY] = {0};
change_array(array, SIZE_ARRAY);
printf("Array : ");
for(int i = 0 ; i < SIZE_ARRAY ; i++)
{
printf("%d ", array[i]);
}
}
void change_array(int *array, int size)
{
for(int i = 0 ; i < size ; i++)
{
array[i] = 5;
}
}
It yields :
Array : 5 5 5 5 5 5 5 5 5 5
I like it because it does not make use of dynamic allocation, but I have trouble understand how it works. From what I understand, array gets converted into a pointer when entering the function change_array. But when I was changing the value of byte in the previous example, I was doing *byte = 5. Here, I am doing array[i] = 5 and not *array[i] = 5.
Finally, I want to change the previous example to modify array based on a global array :
#include <stdio.h>
#define SIZE_ARRAY 10
int global_array[10] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5};
void change_array(int *array, int size);
int main()
{
int array[SIZE_ARRAY] = {0};
change_array(array, SIZE_ARRAY);
printf("Array : ");
for(int i = 0 ; i < SIZE_ARRAY ; i++)
{
printf("%d ", array[i]);
}
}
void change_array(int *array, int size)
{
array = global_array;
}
It yields :
Array : 0 0 0 0 0 0 0 0 0 0
Why is it so ? What to I need to change to make it work ?
Thanks.
Consider your first program.
#include <stdio.h>
void change_byte(int *byte);
int main()
{
int byte = 0;
change_byte(&byte);
printf("Byte : %d \r\n", byte);
}
void change_byte(int *byte)
{
*byte= 5;
}
In this program the object byte is passed to the function change_byte by reference through a pointer to it
change_byte(&byte);
In C passing by reference means passing an object indirectly through a pointer tp it.
So dereferencing the pointer byte declared as a function parameter
void change_byte(int *byte);
you get a direct access to the pointed object byte of the type int defined in main.
Now let's consider your second program
#include <stdio.h>
#define SIZE_ARRAY 10
void change_array(int *array, int size);
int main()
{
int array[SIZE_ARRAY] = {0};
change_array(array, SIZE_ARRAY);
printf("Array : ");
for(int i = 0 ; i < SIZE_ARRAY ; i++)
{
printf("%d ", array[i]);
}
}
void change_array(int *array, int size)
{
for(int i = 0 ; i < size ; i++)
{
array[i] = 5;
}
}
In main you declared an integer array
int array[SIZE_ARRAY] = {0};
Array designators used in expressions with rare exceptions are converted to pointers to their first elements.
Thus this call
change_array(array, SIZE_ARRAY);
is equivalent to
change_array( &array[0], SIZE_ARRAY);
So dereferencing the pointer within the function you can change the first element of the array defined in main.
But array elements are stored in a continuous extent of memory. So using the pointer arithmetic and having a pointer to the first element of an array you can access all elements of the array.
In fact all elements of the array array are passed to the function change_array by reference through a pointer to the first element of the array.
For example the for loop within the function you could rewrite like
for(int i = 0 ; i < size ; i++)
{
*( array + i ) = 5;
}
Now let's consider your third program.
#include <stdio.h>
#define SIZE_ARRAY 10
int global_array[10] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5};
void change_array(int *array, int size);
int main()
{
int array[SIZE_ARRAY] = {0};
change_array(array, SIZE_ARRAY);
printf("Array : ");
for(int i = 0 ; i < SIZE_ARRAY ; i++)
{
printf("%d ", array[i]);
}
}
void change_array(int *array, int size)
{
array = global_array;
}
As it was pointed out already the array array passed to the function change_array is converted to a pointer to its first element.
You may imagine the function call and its definition the following way (I will rename the first function parameter that to avoid name ambiguity).
change_array(array, SIZE_ARRAY);
//...
void change_array( /* int *parm_array, int size */)
{
int * parm_array = array;
int size = SIZE_ARRAY;
parm_array = global_array;
}
That is function parameters are its local variables. The parameter parm_array is alive until the function stops its execution.
Thus this statement
parm_array = global_array;
assign the pointer to the first element of the global array global_array to the local variable parm_array of the function. This assignment does not touch in any way the array array defined in main. It only changes the local variable parm_array declared in the function change_array.
To achieve the expected by you result you could define in main a pointer that is initialized by the array array. And in the function change_array you could reassigned the pointer with the array global_array passing it to the function by reference the same way as you passed the object byte in your first program.
Here is a demonstrative program.
#include <stdio.h>
#define SIZE_ARRAY 10
int global_array[10] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5};
void change_array( int **array_ptr );
int main()
{
int array[SIZE_ARRAY] = {0};
int *array_ptr = array;
change_array( &array_ptr );
printf("Array : ");
for(int i = 0 ; i < SIZE_ARRAY ; i++)
{
printf("%d ", array_ptr[i]);
}
}
void change_array( int **array_ptr )
{
*array_ptr = global_array;
}
The program output is'
Array : 5 5 5 5 5 5 5 5 5 5
For a better understanding (and exercise), edit your function
void change_array(int *array, int size)
{
array = global_array;
}
to
void change_array(int *array, int size)
{
array = global_array;
for (int i=0; i < size; ++i)
printf("%d ", array[i]);
}
Ask yourself, what the output 'means'.

Something wrong with different IDE xcode and vs

I am using both Xcode and VS2017.But the code below works fine in Xcode,and get right output.But in vs, when using the function Printlist(),it stop working and run into loop:
Please input the number of vertexes:
5
Please input the number of edges:
6
Please input each vertex's imformation:
A
B
C
D
E
Please input the relationship between two vertexes:
A B
A D
B C
C D
B E
C E
The Adjacency Matrix you've entered is:
0 1 0 1 0
1 0 1 0 1
0 1 0 1 1
1 0 1 0 0
0 1 1 0 0
The converted adjacency list is:
(0)A->3 1
(1)B->4 2 0
(2)->4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4 3 4................
The program is to create an adjacency matrix and convert it to list. I am searching for a long time on net. But no use. Please help or try to give some ideas how to achieve this.
Thanks in advance:)
#include <stdio.h>
#include <stdlib.h>
#define vexnum 20
#define isLetter(a) ((((a)>='a')&&((a)<='z')) || (((a)>='A')&&((a)<='Z')))
int visited[vexnum];
typedef struct {
char vexs[vexnum];
int AdjMatrix[vexnum][vexnum];
int n, e; //VEXNUM and EDGENUM
}MGraph;
typedef struct ArcNode
{
int adjvex;
struct ArcNode *nextarc;
}ArcNode;
typedef struct VNode
{
char data;
ArcNode *firstarc;
}VNode, AdjList[vexnum];
int GetPosition(MGraph G, char ch)
{
int i;
for (i = 0; i<G.n; i++)
{
if (G.vexs[i] == ch)
return i;
}
return -1;
}
void CreatMGraph(MGraph *G, int n, int e)
{
int i, j, k;
int p = 0, q = 0;
char a, b;
printf("Please input each vertex's imformation:\n");
for (i = 0; i<n; i++)
{
do
{
G->vexs[i] = getchar();
} while (!isLetter(G->vexs[i]));
}
for (i = 0; i<n; i++)
{
for (j = 0; j<n; j++)
{
G->AdjMatrix[i][j] = 0;
}
}
printf("Please input the relationship between two vertexes:\n");
for (k = 0; k<G->e; k++)
{
do
{
a = getchar();
} while (!isLetter(a));
do
{
b = getchar();
} while (!isLetter(b));
p = GetPosition(*G, a);
q = GetPosition(*G, b);
G->AdjMatrix[p][q] = G->AdjMatrix[q][p] = 1;
}
}
void PrintAdjMatrix(MGraph G)
{
int i, j;
printf("The Adjacency Matrix you've entered is:\n");
for (i = 0; i<G.n; i++)
{
for (j = 0; j<G.n; j++)
{
printf("%d ", G.AdjMatrix[i][j]);
if (j == G.n - 1)
printf("\n");
}
}
}
void MatrixToList(MGraph G, AdjList *L)
{
int i, j;
ArcNode *p;
for (i = 0; i<G.n; i++)
{
L[i]->data = G.vexs[i];
L[i]->firstarc = NULL;
}
for (i = 0; i<G.n; i++)
{
for (j = 0; j<G.n; j++)
{
if (G.AdjMatrix[i][j] == 1)
{
if (L[i]->firstarc == NULL)
{
p = (ArcNode *)malloc(sizeof(ArcNode));
p->adjvex = j;
p->nextarc = NULL;
L[i]->firstarc = p;
}
else
{
p = (ArcNode *)malloc(sizeof(ArcNode));
p->adjvex = j;
p->nextarc = L[i]->firstarc;
L[i]->firstarc = p;
}
}
}
}
}
void Printlist(MGraph G, AdjList *L)
{
ArcNode *p;
int i;
for (i = 0; i<G.n; i++)
{
printf("(%d)%c->", i, L[i]->data);
p = (ArcNode *)malloc(sizeof(ArcNode));
p = L[i]->firstarc;
while (p)
{
printf("%d ", p->adjvex);
p = p->nextarc;
}
printf("\n");
}
}
int main()
{
MGraph G;
printf("Please input the number of vertexes:\n");
scanf("%d", &G.n);
printf("Please input the number of edges:\n");
scanf("%d", &G.e);
CreatMGraph(&G, G.n, G.e);
PrintAdjMatrix(G);
AdjList *L = NULL;
L = (AdjList *)malloc(sizeof(AdjList));
MatrixToList(G, L);
printf("The converted adjacency list is:\n");
Printlist(G, L);
return 0;
}
The subscripting of parameter L in functions MatrixToList() and Printlist() is wrong. Consider the parameter declaration AdjList *L: L is a pointer to AdjList, which in turn is defined as an array of vexnum struct VNodes, so L is a pointer to the whole array of struct VNodes. Then with an expression as L[i]->data not the ith node within the array is accessed, but the ith array of a (nonexistent for i > 0) array of arrays (and with ->data the data element in the first node of that ith array). To fix that error, you could change the parameter declaration in the mentioned functions to AdjList L as well as every instance of L[i]-> in those functions to L[i]. and call
MatrixToList(G, *L);
and
Printlist(G, *L);

Heapsort for any type of elements doesn't work

The task was to write heapsort for unknown type of elements in array (using only C code), but my code doesn't work. FOr the following numbers output is '-100 7 -4 0 33 -3 67 1 5 44' I also tried to use the same code for int input only and it worked perfectly. So I think the problem is in changing it to any type of input.
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <memory.h>
typedef int typeEl;
int compare(const void* a, const void* b)
{
return (*(typeEl*)a - *(typeEl*)b);
}
void swap(void* a, void* b, size_t sizeOfElem) {
void* tmp = calloc(1,sizeOfElem);
memcpy(tmp, a, sizeOfElem);
memcpy(a, b, sizeOfElem);
memcpy(b, tmp, sizeOfElem);
}
void heapify (int pos, int n, void* arr, size_t sizeOfElem, int (*comp)(const void* c, const void* d)) {
while (2 * pos + 1 < n) {
int t = 2 * pos +1;
if (2 * pos + 2 < n && ((char *)arr + (2*pos+2)*sizeOfElem) >= ((char *)arr + t*sizeOfElem))
{
t = 2 * pos + 2;
}
if (comp((void *) ((char *)arr + pos*sizeOfElem), ((char *)arr + t*sizeOfElem))<0) {
swap((void *) ((char *)arr + pos*sizeOfElem), (void *) ((char *)arr + t*sizeOfElem), sizeOfElem);
pos = t;
}
else break;
}
}
void heap_make(int n, void* arr, size_t sizeOfElem)
{
for (int i = n - 1; i >= 0; i--)
{
heapify(i, n, arr, sizeOfElem, compare );
}
}
void heap_sort(int n, void* arr, size_t sizeOfElem)
{
heap_make(n, arr, sizeOfElem);
while(n>0)
{
swap((void *) ((char *)arr), (void *) ((char *)arr + (n-1)*sizeOfElem), sizeOfElem);;
n--;
heapify(0,n, arr, sizeOfElem, compare);
}
}
int main() {
int n;
int m[10] = {1,-3,5,-100,7,33,44,67,-4, 0};
heap_sort(10, m, sizeof(int));
for (n=0; n<10; n++)
printf ("%d ",m[n]);
return 0;
}
Anyone can advise? Thx for the help!
It can be very hard to decode someone else's code - especially when you are doing all kinds of complicated indexing etc. I had an old copy of a heapify lying around (from an earlier answer - https://stackoverflow.com/a/19749300/1967396 ) and I modified it to work for any type - and to include a full sort.
This doesn't completely answer the question "why is your code not working" - but it does show you some simple techniques you might want to implement as you try to answer the question. Typically, the more readable your code, the easier it is to debug.
Note that, in order to improve readability, I introduced a couple of extra variables (and additional lines of code) - childLeft and childRight are definitely useful; also, you can index elements once you have established a data type for their pointer - since you had a typedef at the start of your code, I simplified some things by doing
typeEl *array;
after which I could index the array with
array[pos];
which is much more readable (and thus less prone to errors) than
*((void *) ((char *)arr + pos*sizeOfElem))
I also defined swap in terms of the array and the indices of the two elements that needed swapping:
void swap(typeEl *arr, int i, int j)
which again makes the code considerably more readable (note also that I don't have to do a calloc).
Anyway - here is the code:
#include <stdio.h>
// define the type of the array that will be sorted:
typedef double typeEl;
void buildHeap(typeEl array[], int n);
void heapify(typeEl array[], int n, int i);
void heapsort(typeEl array[], int n);
void swap(typeEl array[], int indexA, int indexB);
void printTree(void);
int compare(typeEl a, typeEl b);
typeEl* TREE; // global variable used for printing the entire tree
int main(int argc, char *argv[])
{
typeEl heapArray[] = {1,-3,5,-100,7,33,44,67,-4, 0};
//{0, 1, 2, 3, 4, 5, 6 , 7, 8 ,9 ,10 , 11, 12, 13 ,14 ,15};
int n = sizeof(heapArray)/sizeof(typeEl);
TREE = heapArray;
printf("initial tree:\n");
printTree();
heapsort(heapArray, n);
printf("after heapify\n");
printTree();
printf("as a sorted array:\n");
for(int ii = 0; ii < n; ii++) printf("%d ", (int)heapArray[ii]);
printf("\n");
return 0;
}
void printTree(void)
{
// lazy way to print the entire tree...
typeEl* array = TREE;
printf(" %3d\n ", (int)array[0]);
printf(" %3d %3d\n", (int)array[1], (int)array[2]);
printf(" %3d %3d %3d %3d\n", (int)array[3], (int)(int)array[4], (int)array[5], (int)array[6]);
printf(" %3d %3d %3d\n", (int)array[7], (int)array[8], (int)array[9]);
printf("\n");
}
void heapsort(typeEl array[], int n) {
int i;
buildHeap(array, n);
for(i = 1; i < n; i++) {
buildHeap(array + i, n - i);
}
}
void buildHeap(typeEl array[], int n)
{
// change starting condition
int i = n/2;
while(i > 0) heapify(array, n,--i);
}
void heapify(typeEl array[], int n, int i)
{
// mark nodes initially as -1 to distinguish from "valid" zero
int childLeft = -1, childRight = -1;
int largest = i;
// see if we have valid child nodes:
if( 2 * i + 1 < n ) childLeft = 2 * i + 1;
if( 2 * i + 2 < n ) childRight = 2 * i + 2;
// see if any nodes are invalid now:
if(childLeft < 0 && childRight < 0) return;
if(childLeft < 0) childLeft = childRight; // can't happen, ever.
if(childRight < 0) childRight = childLeft;
// printf("child left [%i] = %i child right [%i] = %i\n", childLeft, array[childLeft], childRight, array[childRight]);
if (compare(array[childLeft], array[i] )) largest = childLeft;
if (compare(array[childRight] , array[largest])) largest = childRight;
if(largest != i)
{
swap(array, i,largest);
heapify(array, n, largest);
}
}
void swap(typeEl array[], int indexA, int indexB)
{
// printf("swap [%i] %i with [%i] %i\n", indexA, array[indexA], indexB, array[indexB]);
typeEl temp = array[indexA];
array[indexA] = array[indexB];
array[indexB] = temp;
}
int compare(typeEl a, typeEl b) {
return (a - b>0)?1:0;
}
Sample output:
initial tree:
1
-3 5
-100 7 33 44
67 -4 0
after heapify
67
44 33
7 5 1 0
-3 -4 -100
as a sorted array:
67 44 33 7 5 1 0 -3 -4 -100
As you can see it is sorted high - to - low. Obviously you can change that by simply changing the compare function.

Resources