walsh table for nxn matrix in C - c

I have been trying to understand the walsh table matrix for n-dimension since I am required to write a code that generates the walsh matrix for any given order. I have so far failed to write a working code. Can anyone help me with the algorithm, or suggest something about my program below:(it works for 2x2 and 4x4 but fails for 8x8)
#include<stdio.h>
#include<conio.h>
main()
{
/* Program variables
Dimension variable, n
Loop variables i,j
Two dimensional array for walsh table a[100][100] */
int n,j,i,a[100][100];
clrscr();
// User input to display walsh table
printf("enter the size ");
scanf("%d",&n);
// Iterate rows from 0 to 'n'
for(i=0;i<n;i++)
{
// Iterate columns from 0 to 'n' for each row 'i'
for(j=0;j<n;j++)
{
if(i%2==1 && j%2==1) // for both i & j not divisible by 2, initialize array elements with -1
a[i][j] = -1;
else if(i/2==1 && j/2==1){ // for both i & j, if completely divisble by 2 and dividend is 1
if(j == 3 && i == 3){
a[i][j]=1;
}
else
a[i][j] = -1;
}
else
a[i][j] = 1; // default case initialized to 1
}
a[3][3] = 1;
}
// Output complete walsh table
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
printf("\t%d",a[i][j]);
}
// go to next line after every row
printf("\n");
}
getch();
}

You should be looking at the generation of a Walsh code as a recursive problem. First you generate the 2x2; from that you generate the 4x4, etc. Each time, the next block is generated from the previous one by adding two copies of the lesser-order block in the top-right and bottom-left quadrant, and its inverse in the bottom right hand quadrant. You can do this by creating the matrix once, and working your way through it in increasing block sizes. Here is how that works
UPDATED so it produces the 1 -1 version of the code that you saw on wiki;
UPDATED AGAIN to make it capable of taking an input for the size of the matrix and generate a Walsh matrix of arbitrary size; includes all kinds of error checking and other cool tricks:
FINAL(?) UPDATE Ryyker pointed out that there was a memory error in my code. I found and fixed it - and checked it with valgrind to be sure. It seems to be working fine now.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int **twoDmatrix(int m, int n) {
// create a 2D matrix of arbitrary dimensions
int ii, **M;
M = malloc(m * sizeof(int**));
M[0] = malloc(m*n*sizeof(int*));
for(ii=1; ii<m; ii++) {
M[ii] = M[0] + ii * n;
}
return M;
}
void free2D(int** M) {
// free memory allocated by twoDmatrix()
free(M[0]);
free(M);
}
int isPow2(int n) {
// return 1 if the argument is a valid (positive) power of 2
if(n<=1) return 0;
while(n>1) {
if (n%2==1) return 0;
n = n/2;
}
return 1;
}
void emptyBuf(void) {
while(getchar()!='\n');
return;
}
int main(void) {
int **W;
int N;
int power = 1;
int i,j,k,l,p=0;
while(1==1) {
printf("enter the size of the matrix - must be a positive power of 2\n");
if(scanf("%d", &N)!=1) {
printf("unable to scan input\n");
emptyBuf();
continue;
}
if (!isPow2(N)) {
printf("%d is not a valid power of 2\n", N);
continue;
}
break; // valid input: go on
}
W = twoDmatrix(N,N); // allocate memory for 2D matrix
W[0][0]=1; // this is the 1x1 Walsh code...
while (power < N) {
for(i=0; i<2; i++) {
for(j=0; j<2; j++) {
if (!(i==0 && j==0)) {
for(k=0; k<power; k++) {
for(l=0; l<power; l++) {
if (i==1 && j == 1) {
W[i*power+k][j*power+l] = -W[k][l]; // invert signal
}
else {
W[i*power+k][j*power+l] = W[k][l]; // copy signal
}
}
}
}
}
}
power *=2; // double matrix and repeat
}
// print out result
for(i=0; i<N; i++) {
for(j=0; j<N; j++) {
printf("%2d ", W[i][j]); // <<<<< updated
}
printf("\n");
}
free2D(W); // always remember to free your memory...
}
output:
enter the size of the matrix - must be a positive power of 2
5
5 is not a valid power of 2
enter the size of the matrix - must be a positive power of 2
3
3 is not a valid power of 2
enter the size of the matrix - must be a positive power of 2
0
0 is not a valid power of 2
enter the size of the matrix - must be a positive power of 2
-4
-4 is not a valid power of 2
enter the size of the matrix - must be a positive power of 2
asdf
unable to scan input
enter the size of the matrix - must be a positive power of 2
asdfasdfasdfasdf
unable to scan input
enter the size of the matrix - must be a positive power of 2
16
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 -1 1 -1 1 -1 1 -1 1 -1 1 -1 1 -1 1 -1
1 1 -1 -1 1 1 -1 -1 1 1 -1 -1 1 1 -1 -1
1 -1 -1 1 1 -1 -1 1 1 -1 -1 1 1 -1 -1 1
1 1 1 1 -1 -1 -1 -1 1 1 1 1 -1 -1 -1 -1
1 -1 1 -1 -1 1 -1 1 1 -1 1 -1 -1 1 -1 1
1 1 -1 -1 -1 -1 1 1 1 1 -1 -1 -1 -1 1 1
1 -1 -1 1 -1 1 1 -1 1 -1 -1 1 -1 1 1 -1
1 1 1 1 1 1 1 1 -1 -1 -1 -1 -1 -1 -1 -1
1 -1 1 -1 1 -1 1 -1 -1 1 -1 1 -1 1 -1 1
1 1 -1 -1 1 1 -1 -1 -1 -1 1 1 -1 -1 1 1
1 -1 -1 1 1 -1 -1 1 -1 1 1 -1 -1 1 1 -1
1 1 1 1 -1 -1 -1 -1 -1 -1 -1 -1 1 1 1 1
1 -1 1 -1 -1 1 -1 1 -1 1 -1 1 1 -1 1 -1
1 1 -1 -1 -1 -1 1 1 -1 -1 1 1 1 1 -1 -1
1 -1 -1 1 -1 1 1 -1 -1 1 1 -1 1 -1 -1 1
For reference see http://my.fit.edu/~kostanic/Personal%20Communication%20Systems/ECE%205221%20-%20Lecture14.pptx - from which I took the following:
POSTSCRIPT
A note about the twoDmatrix() function. I wrote this function because there is no direct way to allocate a 2D matrix of unknown size in C. So this function creates an array of pointers to int - one pointer for each row in the matrix; and it also allocates a block of memory - one for each element in the array. It then associates one pointer with the start of each row in the matrix, so that you can access the elements with the usual W[i][j] indexing. This makes it look like the first row of the array is really long (it points to the entire NxN block), the second row is a little shorter, etc. But it's just a trick so you can access the elements of the array with the usual syntax. Imagine that you have a 3x3 array filled with the numbers 0 to 8 - then things look like this:
pointer values
W[0] 0 1 2
W[1] 3 4 5
W[2] 6 7 8
But another way of looking at it is this:
0 1 2 3 4 5 6 7 8
^ W[0]
^W[1]
^W[2]
What this means is that you could access the element W[0][6] - its value would be the same as W[1][3] which again is the same as W[2][0].
When you no longer need the function, you have to free the two blocks of memory - first the data block, and then the pointer block. This is the role of the free2D() function.

Modified Your code: There are three things I did:
1) formatted with more blocks {...} for readability
2) initialized array a[100][100] for all elements using memset()
3) added an extra getchar() (my system uses that instead of getch() ), and commented clrscr()
It ran for 4x4 and 8x8 (but the output does not look correct, you have more work to do there):
main()
{
/* Program variables
Dimension variable, n
Loop variables i,j
Two dimensional array for walsh table a[100][100] */
int n,j,i,a[100][100];
//clrscr();
// User input to display walsh table
memset(a, 0, 100*100);
printf("enter the size ");
scanf("%d",&n);
// Iterate rows from 0 to 'n'
for(i=0;i<n;i++)
{
// Iterate columns from 0 to 'n' for each row 'i'
for(j=0;j<n;j++)
{
if(i%2==1 && j%2==1) // for both i & j not divisible by 2, initialize array elements with -1
{
a[i][j] = -1;
}
else if(i/2==1 && j/2==1)
{ // for both i & j, if completely divisble by 2 and dividend is 1
if(j == 3 && i == 3)
{
a[i][j]=1;
}
}
else
{
a[i][j] = -1;
}
}
a[i][j] = 1; // default case initialized to 1
}
a[3][3] = 1;
// Output complete walsh table
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
printf("\t%d",a[i][j]);
}
// go to next line after every row
printf("\n");
}
getchar();
getchar();
}

Related

logical multiplication of matrices A and B by the operation "AND" and "OR" in C

This is the question:
A logical matrix is a matrix in which all its elements are either 0 or
1.
We define logical multiplication of matrices A and B by the operation
defined below, where "·" is the logical AND operation, and "+" is the
logical OR operation.
In this assignment, you will create two 5x5 logical matrices and find
the corresponding matrix which will be created from "multiply" these 2
matrices
Define global SIZE equals to 5 (Already defined in the template)
Write a function that gets a matrix reference and reads the input
to the matrix from the user. If the input is non-zero replace it by 1.
If the user did not enter enough values before the end of the line,
the remaining cells in the matrix will be populated with zeros. Also
make sure if the user inputs too many characters, you only take what's
needed and discard the remaining input. (Eg: 1509 is a 2x2 matrix with
values 1101, and ‘1 5 ‘ is also a 2x2 matrix with values 1111, the
highlighted whitespace is taken as a 1 as discussed above.)
Function signature: void read_mat(int mat[][SIZE])
Write a function that multiplies, as defined above, two matrices
and enters the results into a third matrix with suitable dimensions.
Function signature: void mult_mat(int mat1[][SIZE],int mat2[][SIZE], int result_mat[][SIZE])
Write a function that prints a matrix into the screen. Please use
“%3d” for printing format to make it look nice as shown below.
Function signature: void print_mat(int mat[][SIZE])
Write the main program which uses the functions above. The program
reads the matrices values from the user, multiplies them and prints
the result matrix on the screen.
The function definitions given are intentional with the return
statements as void. Do not change them. Arrays are transferred between
functions as references rather as primitives like variables. So the
function definitions are perfectly valid. Also, there is no limit on
the input from the user. You can read only the required digits, and
then stop reading, and discard the remaining input.
Here is my code:
#include <stdio.h>
#define SIZE 5
void read_mat(int mat[][SIZE],int size)
{
int i = 0, j = 0, k = 0;
char c;
c=getchar();
while(c!='\n' && k<size*size){
if(c!='0'){
mat[i][j]=1;
j++;
}
else{
mat[i][j]=0;
j++;
}
if (j >= size){
j = 0;
i++;
}
if (i >= size){
return;
}
c=getchar();
k++;
}
}
void mult_mat(int mat1[][SIZE], int mat2[][SIZE], int result_mat[][SIZE])
{
int i,j,k;
for (i = 0; i <SIZE; ++i){
for (j = 0; j <SIZE; ++j)
{
result_mat[i][j] = 0;
for (k = 0; k < SIZE; ++k)
result_mat[i][j] += mat1[i][k] * mat2[k][j];
if(result_mat[i][j]!=0){
result_mat[i][j]=1;
}
}
}
}
void print_mat(int mat[][SIZE],int size)
{
int i, j;
for (i = 0; i < SIZE; i++) {
for (j = 0; j < SIZE; j++)
printf("%3d", mat[i][j]);
printf("\n");
}
//Please use the "%3d" format to print for uniformity.
}
int main()
{
int mat1[][SIZE]={ 0 }, mat2[][SIZE]={ 0 }, res_mat[][SIZE]={0};
printf("Please Enter Values For Matrix 1\n");
read_mat(mat1,SIZE);
printf("Please Enter Values For Matrix 2\n");
read_mat(mat2,SIZE);
mult_mat(mat1,mat2,res_mat);
printf("The First Matrix Is :- \n");
print_mat(mat1,SIZE);
printf("The Second Matrix Is :- \n");
print_mat(mat2,SIZE);
printf("The Resultant Matrix Is :- \n");
print_mat(res_mat,SIZE);
return 0;
}
The input and output should be like this:
Please Enter Values For Matrix 1
111000654987010
Please Enter Values For Matrix 2
11 53
The First Matrix Is :-
1 1 1 0 0
0 1 1 1 1
1 1 0 1 0
0 0 0 0 0
0 0 0 0 0
The Second Matrix Is :-
1 1 1 1 1
1 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
The Resultant Matrix Is :-
1 1 1 1 1
1 0 0 0 0
1 1 1 1 1
0 0 0 0 0
0 0 0 0 0
But when I run the program, this message appears:
exception thrown: Run-Time Check Failure #2 - Stack around the variable 'mat2' was corrupted.
and the output isn't right and I am getting some elements has a junk values:
Please Enter Values For Matrix 1
111000654987010
Please Enter Values For Matrix 2
11 53
The First Matrix Is :-
1 1 1 0 0
0 1 1 1 1
1 1 1 1 1
1 1-858993460-858993460-858993460
-858993460-858993460-858993460-858993460 1
The Second Matrix Is :-
1 1 1 1 1
-858993460-858993460-858993460-858993460-858993460
-858993460-858993460 1 1 1
1 1 1 1 1
1 1 1 1 1
The Resultant Matrix Is :-
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
Another question:
if I entered to the mat1 a big string it's calculated directly without letting me enter a string to mat2 how do I solve this problem ?
int mat1[][SIZE]={ 0 }
will declare a 1x5 matrix. Change it to
int mat1[SIZE][SIZE]={ 0 }

Looking for faults in algorithm for organizing a one-way railway station traffic

I wrote the code below for solving this railway station traffic programming contest question. ( You may read comments and proposed solutions here). However, there are a few exceptional cases for which this code won't work. What are they?
#include <stdio.h>
#include <stdlib.h>
int main(){
int n, i,j;
int * array;
scanf("%i",&n);
array = malloc(sizeof(int) * n);
for(i=0;i<n;++i) scanf("%i",&array[i]);
for(i=0;i<n;++i){
if(i+1 == array[i]) array[i] = -1;
else{
if(array[i] < i+1){
for(j=0;j<i;++j){
if(array[i] == j+1){
if(array[j] == -1){
printf("No\n");
return 0;
}
else array[i] = array[j] = -1;
}
}
}
}
}
for(i=0;i<n;++i) if(array[i] != -1) break;
if(i == n) printf("Yes\n");
else printf("No\n");
return 0;
}
P.S.: I'm assuming this program takes one entry at each time ( rather than waiting for an 0 for signaling the end of input ).
What this code is supposed to do:
1) I'm assuming you've already read what's in this link.
2) After copying a sequence into an array, we must verify whether or not this sequence is valid.
So we use the following algorithm:
Iterate over the sequence, starting from the first element.
If element = element's index + 1 ( because C lists are zero-indexed ), then element = -1.
Otherwise, if and only if element < element's index: We look for a previous element for which ( current element == previous' element index + 1 ) is valid. If this element is found, then now both current element and previous element are changed to -1. If previous element has already been changed before ( that is, it's already -1 ) then this is not a valid sequence.
If after iterating over the list like this any elements are still left, this is not a valid sequence.
Examples:
Example 1
Array: 5 4 3 2 1
5 : 5 > 0 + 1, skip. 4: 4 > 1 + 1, skip. 3: 3 == 2 + 1. Then 3 -> -1.
Array: 5 4 -1 2 1
2 : 2 < 3 + 1. 4 has an index of 1 and 1 + 1 = 2.
Array: 5 -1 -1 -1 1
1: 1 < 4 + 1. 5 has an index of 0 and 0 + 1 = 1.
Array: -1 -1 -1 -1 -1
Therefore this sequence is valid.
Example 2
Array: 5 4 1 2 3
5: 5 > 0 + 1, skip. 4: 4 > 1 + 1, skip. 1: 1 < 2 + 1. 5 has an index
of 0.
Array: -1 4 -1 2 3
2: 2 < 3 + 1. 4 has an index of 1.
Array: -1 -1 -1 -1 3
3: 3 < 4 + 1. -1 ( at position 2 ) has an index of 2. 2 + 1 = 3.
Therefore the sequence is not valid.
Here is an example of an input where your code will give the wrong output:
5
3 4 2 5 1
Your description gave a translation of the code in English, but did not give insight into why that algorithm would solve the problem. So, I just went for a solution where an extra array is used for keeping track of the carriages that are in the station, which will have to function like a stack (First-in-last-out):
#include <stdio.h>
#include <stdlib.h>
int main(){
int n, i;
int carriageAtA = 1;
int * array;
int * station;
int stationSize = 0;
// Read input
scanf("%i",&n);
array = malloc(sizeof(int) * n);
station = malloc(sizeof(int) * n);
for(i=0;i<n;++i) scanf("%i",&array[i]);
// Iterate the desired carriages in sequence
for(i=0;i<n;++i) {
// While the last one in the station is not what we need:
while ((!stationSize || station[stationSize-1] != array[i]) && carriageAtA <= n) {
printf("Move %i from A to station\n", carriageAtA);
// Last carriage in station B is not what we need, so pull one in from A:
station[stationSize] = carriageAtA;
stationSize++; // There is now one more carriage in the station
carriageAtA++; // This is the next carriage at A
}
if (!stationSize || station[stationSize-1] != array[i]) {
// Could not find desired carriage at A nor at station. Give up.
printf("No\n");
return 0;
}
// Drive last carriage at station to B:
printf("Move %i from station to B\n", array[i]);
stationSize--;
}
printf("Yes\n");
return 0;
}
The additional printf calls are just for getting a view of the process. Remove them when you are satisfied.

Boolean Table in 2D array C

I have some dificulties in creating the following array. My task is to fill using recursion a 2D array with all the possible combinations of 0 and 1 taken m times in lexical order. Mathematically speaking there are 2 ^ m combinations.My program just fills the first 3 rows of the array with the same order 0 1 0 1 and then just prints for the rest of the rows 0 0 0 0.
Example
m=4
0 0 0 0
0 0 0 1
0 0 1 0
0 0 1 1
0 1 0 0
0 1 0 1
0 1 1 0
0 1 1 1
1 0 0 0
1 0 0 1
1 0 1 0
1 0 1 1
1 1 0 0
1 1 0 1
1 1 1 0
1 1 1 1
This is my code so far and I appreciate if someone could correct it and explain me what I am doing wrong as I can't spot the mistake myself
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
void *safeMalloc(int n) {
void *p = malloc(n);
if (p == NULL) {
printf("Error: malloc(%d) failed. Out of memory?\n", n);
exit(EXIT_FAILURE);
}
return p;
}
void combine(int** arrTF,int m,int n,int row,int col){
if(m==0){
if(row<pow(2,m)){
row++;
combine(arrTF,n,n,row,0);
}else{
return;
}
}else{
arrTF[row][col]=0;
col++;
combine(arrTF,m-1,n,row,col);
arrTF[row][col]=1;
col++;
combine(arrTF,m-1,n,row,col);
}
}
int main(int argc, char *argv[]) {
int m
scanf("%d",&m);
int** arrTF;
arrTF = safeMalloc(pow(2,m)*sizeof(int *));
for (int r=0; r < pow(2,m); r++) {
arrTF[r] = safeMalloc(m*sizeof(int));
}
for(int i=0;i<pow(2,m);i++){
for(int j=0;j<m;j++){
arrTF[i][j]=0;
}
}
combine(arrTF,m,m,0,0);
for(int i=0;i<pow(2,m);i++){
for(int j=0;j<m;j++){
printf("%d ",arrTF[i][j]);
}
printf("\n");
}
return 0;
}
You want all the possible (2^m) combinations of 0's and 1's taken m times in lexical order and you are using a 2D array to store the result.
Things would be very easy if you just want to print all the possible combination of 0's and 1's instead of storing it in 2D array and printing array later.
Storing a combination of 0's and 1's to 2D array is a little bit tricky as every combination is one element of your 2D array.
You want to generate the combination of 0's and 1's in accordance with the recursive algorithm.
So, let's say, at some stage if your algorithm generates the combination 0010 which is stored in an element in 2D array.
And the next combination would be 0011 which the recursive algorithm will generate just by changing the last number from 0 to 1 in the last combination (0010).
So, that means everytime when a combination is generated, you need to copy that combination to its successive location in 2D array.
For e.g. if 0010 is stored at index 2 in 2D array before the algorithm starts computing the next combination, we need to do two things:
Copy the elements of index 2 to index 3
Increase the row number so that last combination will be intact
(Say, this is 2D array)
|0|0|0|0| index 0
|0|0|0|1| index 1
|0|0|1|0| index 2 ---> copy this to its successive location (i.e. at index 3)
|0|0|1|1| index 3 ---> Last combination (index 2) and the last digit is changed from 0 to 1
.....
.....
.....
This we need to do for after every combination generated.
Now, I hope you got where you are making the mistake.
Few practice good to follow:
If you want to allocate memory as well as initialized it with 0, use calloc instead of malloc.
Any math function you are calling again and again for the same input, it's better to call it once and store the result in a variable and use that result where ever required.
Do not include any header file which is not required in your program.
Once done, make sure to free the dynamically allocated memory in your program.
I have made the corrections in your program:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
void *safeMalloc(size_t n, size_t size) {
void *p = calloc(n, size);
if (p == NULL) {
printf("Error: calloc(%zu) failed. Out of memory!\n", n);
exit(EXIT_FAILURE);
}
return p;
}
void deallocate(int ** ptr, int row) {
for(int i = 0; i<row; i++)
free(ptr[i]);
free(ptr);
}
void combine(int **arrTF, int m, int max_col, int max_row) {
static int row;
if(m==0){
int i;
if (row<(max_row - 1))
{
for(i=0; i<max_col; i++)
arrTF[row+1][i] = arrTF[row][i];
}
row++;
return;
} else {
arrTF[row][max_col-m] = 0;
combine(arrTF, m-1, max_col, max_row);
arrTF[row][max_col-m] = 1;
combine(arrTF, m-1, max_col, max_row);
}
}
int main(int argc, char *argv[]) {
int** arrTF;
int m, max_row;
printf ("Enter number: \n");
scanf("%d", &m);
max_row = pow(2, m);
arrTF = safeMalloc(max_row, sizeof(int *));
for (int r=0; r<max_row; r++) {
arrTF[r] = safeMalloc(m, sizeof(int));
}
combine(arrTF, m, m, max_row);
for(int i=0; i<max_row; i++) {
for(int j=0; j<m; j++) {
printf("%d ", arrTF[i][j]);
}
printf("\n");
}
deallocate(arrTF, max_row);
return 0;
}
Output:
$ ./a.out
Enter number:
2
0 0
0 1
1 0
1 1
$ ./a.out
4
0 0 0 0
0 0 0 1
0 0 1 0
0 0 1 1
0 1 0 0
0 1 0 1
0 1 1 0
0 1 1 1
1 0 0 0
1 0 0 1
1 0 1 0
1 0 1 1
1 1 0 0
1 1 0 1
1 1 1 0
1 1 1 1
Hope this helps.

Sort rows of a matrix by the first element in the row C

I have an matrix:
3 3 -1 -1
1 1 1 -1
6 6 6 6
0 -1 -1 -1
What I need is this output:
0 -1 -1 -1
1 1 1 -1
3 3 -1 -1
6 6 6 6
How can I proprely sort it like this?
I hope this code help you. You should do the commented parts yourself to get the result.
#define RAW_NUM 4
#define COL_NUM 4
int main () {
int ** matrix = malloc (RAW_NUM * sizeof (int *));
// you should be sure about successful allocation
int i, j;
for (i=0; i < RAW_NUM; i++) {
matrix [i]= malloc (COL_NUM * sizeof (int);
// you should be sure about successful allocation
}
// fill the matrix here
for (i=0; i < RAW_NUM - 1; i++) {
for (j=i +1; j < RAW_NUM; i++)
if (*matrix [i] > *matrix [j])
{
// please swap matrix [i] and matrix [j] here
}
}
}
I'm just posting it so if anyone who is interested in Python might find it useful.
#input array
array = [[5,8], [1,2], [2,3], [7,9], [4,6]]
#sorting array according to first element of intervals.
array.sort(key = lambda x:x[0])

Count number of occurrences of each unique number: algorithm almost works

I am trying to work my way up from the beginning in C and making sure I understand every little thing before moving on. Today, my goal was to write a program that would take in a list of integers (assume less than 50 integers) and would print a table with the list of unique integers in one side and the number of times it appeared in the other. I have a copy of my function which takes care of counting the number of times it appears.
Quick summary of my function: takes in 2 pointers to arrays, and one integer of how many integers to iterate over. Assumption: we are checking for repeats of some number x. Somewhere in the array, we hit another x. It increments the count for x and turns x into 0 for later purposes.
Sample trials
input: 1 2 1 2 2 1 2
output: 1 appears 3 times. 2 appears 4 times.
input: 1 2 3 1 2 3 1 2 3
output: 1 appears 3 times. 2 appears 3 times. 3 appears 3 times.
input: 1 2 1 3 1 2 3
output: 1 appears 3 times. 2 appears 2 times. 3 appears 1 times.
Although the program is working for the most part, I want to make sure it works completely. Thus, my issue is that last trial. Why is 3 being read only once when it works for other 2 input sets?
void countOccurrences(int *list, int size, int *uniques){
for (int i = 0, t = 0; i < size; i++){
int temp = list[i];
if (temp == 0){ //If the number was a repeat of another previous number
continue; //skip over it and go to the next element in list
}
uniques[t] = 1;
for (int j = i+1; j <= size; j++){ //this iterates through list for any repeats of temp
if (temp == list[j]){ //All repeats of temp turn to 0
uniques[i]++;
list[j] = 0;
}
}
t++;
}
}
It is because, 3 comes as last number and you reset the count of occurrence to 1
uniques[t] = 1;
and for loop doesn't run at all since thats the last number, you are not looking back in the array.
I would simply write this program as below.Given list has values >=0
for (int i = 0; i < size; i++){ //this iterates through list for any repeats of temp
uniques[list[i]]++;
}
For a list with any values, use a hash table data structure
I wouldn't go stomping over the original data.
High level view:
for each element
if it apeared before
increment it's count
else
record it's first occurence
Say you need to count the contents of an N element array, it can't contain more than N different elements. One simple way of representing the counts is to have an array of values and counts, and a number of used entries (different values seen). This would be along the lines:
#define N ...
struct {
int value, cnt;
} count[N];
int entries = 0;
Your check to see if the value v is already there is:
for(k = 0; k < entries && count[k].value != v; k++)
;
if(k == entries) {
/* Not found */
count[k].value = v;
count[k].cnt = 1;
entries++;
}
else {
/* Found it */
count[k].value++;
}
Just need to wrap this up with the code to comb your data array...
(Yes, this is quite inefficient; for serious use a smarter/faster structure to keep the values would be needed).
There are several problems with this code that we can illustrate with some more complete testing. Here's a short, self-contained, compilable (in C99) example (see SSCCE) with some tests and some additional diagnostic results:
#include <stdio.h>
void printArray(char *name, int *list, int size) {
printf ("%s = {",name);
for (int i = 0; i < size; i++) {
printf ("%d ",list[i]);
}
printf ("}\n");
}
void countOccurrences(int *list, int size, int *uniques, int *values) {
for (int i = 0, t = 0; i < size; i++) {
int temp = list[i];
if (temp == 0) {
//If the number was a repeat of another previous number
continue;
//skip over it and go to the next element in list
}
uniques[t] = 1;
values[t] = temp;
for (int j = i+1; j <= size; j++) {
//this iterates through list for any repeats of temp
if (temp == list[j]) {
//All repeats of temp turn to 0
uniques[i]++;
list[j] = 0;
}
}
t++;
}
}
void test(int *x, int size) {
const int n = 10;
int uniques[n],values[n];
for (int i = 0; i < n; i++) {uniques[i] = 0; values[i] = -1; }
countOccurrences (x,size,uniques,values);
printArray ("uniques",uniques,sizeof(uniques)/sizeof(*uniques));
printArray ("values ",values,sizeof(values)/sizeof(*uniques));
}
int main (int argc, char* argv[]) {
int x1[] = {1, 2, 1, 2, 2, 1, 2};
int x2[] = {1, 2, 3, 1, 2, 3, 1, 2, 3};
int x3[] = {1, 2, 1, 3, 1, 2, 3};
int x4[] = {3, 2, 1, 3, 1, 2, 3};
test(x1,sizeof(x1)/sizeof(*x1));
test(x2,sizeof(x2)/sizeof(*x2));
test(x3,sizeof(x3)/sizeof(*x3));
test(x4,sizeof(x4)/sizeof(*x4));
return 0;
}
(EDITED thanks to #Matt McNabb's advice, by refactoring common code into the test() function)
... for which the output is:
uniques = {3 4 0 0 0 0 0 0 0 0 }
values = {1 2 -1 -1 -1 -1 -1 -1 -1 -1 }
uniques = {4 3 3 0 0 0 0 0 0 0 }
values = {1 2 3 -1 -1 -1 -1 -1 -1 -1 }
uniques = {4 2 1 1 0 0 0 0 0 0 }
values = {1 2 3 -1 -1 -1 -1 -1 -1 -1 }
uniques = {3 2 3 0 0 0 0 0 0 0 }
values = {3 2 1 -1 -1 -1 -1 -1 -1 -1 }
The first test gives you the expected output. The second test shows that there is an extra count for the first item in the list. This can be fixed by changing:
for (int j = i+1; j <= size; j++){
to
for (int j = i+1; j < size; j++){
... because the code is counting one space beyond the end of the data. The output with this bug fixed is:
uniques = {3 4 0 0 0 0 0 0 0 0 }
values = {1 2 -1 -1 -1 -1 -1 -1 -1 -1 }
uniques = {3 3 3 0 0 0 0 0 0 0 }
values = {1 2 3 -1 -1 -1 -1 -1 -1 -1 }
uniques = {3 2 1 1 0 0 0 0 0 0 }
values = {1 2 3 -1 -1 -1 -1 -1 -1 -1 }
uniques = {3 2 2 0 0 0 0 0 0 0 }
values = {3 2 1 -1 -1 -1 -1 -1 -1 -1 }
The third and fourth test results are harder to interpret because it isn't so obvious what the intended output should be. The counting function appears to be intended to report counts of unique numbers in the order in which it finds those numbers in list. With the third test, however, the first appearance of "3" is at the fourth item in the list. Changing:
uniques[i]++;
to
uniques[t]++;
... means that the count is output as the tth item in the count list, giving the output:
uniques = {3 4 0 0 0 0 0 0 0 0 }
values = {1 2 -1 -1 -1 -1 -1 -1 -1 -1 }
uniques = {3 3 3 0 0 0 0 0 0 0 }
values = {1 2 3 -1 -1 -1 -1 -1 -1 -1 }
uniques = {3 2 2 0 0 0 0 0 0 0 }
values = {1 2 3 -1 -1 -1 -1 -1 -1 -1 }
uniques = {3 2 2 0 0 0 0 0 0 0 }
values = {3 2 1 -1 -1 -1 -1 -1 -1 -1 }
This output is correct now, but it is difficult to interpret the counts found in uniques without the values array that I've added to the code. See that, in the last test case, the first count is the number of 3s in list, not the number of 1s, for instance.
Finally, it is generally poor practice to modify a parameter to a function at all. It is necessary to do so in C because you can't return an array from a function but modifying the arrays pointed to by uniques and values is generally tolerable because they are explicitly available to return results outwards from the function. Modifying a parameter used to supply input data to a function, though, as countOccurrences() does with list is generally unwise because that means the code that uses countOccurrences() has to make a copy of list before passing the pointer to that list to countOccurrences(), if it wants to use the original content of list for some other purpose as well.
If we know that the integers to be counted are all less than or equal to than the size of the uniques array, the function suggested by #Saravana Kumar is both quicker to run and easier to make correct:
// Requirements:
// uniques initially contains all zeros
// no integer in list is less than zero or greater than sizeof(uniques)/sizeof(int)-1
//
void countOccurrences2 (int *list, int size; int *uniques) {
for (int i = 0; i < size; i++) {
uniques[list[i]]++;
}
}

Resources