Columnar Transposition in C - c

I'm trying to make a columnar transposition in C. The user inputs a string and key. The length of the key determines how many columns there are.To encryp the message the key must be sorted alphabetically. Here is an example using the string as hello there and the key as 'KEY'.
I created a function to sort the key alphabetically but I have no clue how to swap the columns.
void gridStr(char *line, char *key);
char encrypt(char *key);
int main(void) {
char key[50];
char line[256];
printf("Enter your string: ");
if (fgets(line, sizeof line, stdin) == NULL) {
fprintf(stderr, "No line read\n");
exit(EXIT_FAILURE);
}
printf("Enter your key: ");
if (fgets(key, sizeof key, stdin) == NULL) {
fprintf(stderr, "No line read\n");
exit(EXIT_FAILURE);
}
int len = strlen(line);
if (len && line[len - 1] == '\n')
line[--len] = '\0';
int len1 = strlen(key);
if (len1 && key[len1 - 1] == '\n')
key[--len]= '\0';
gridStr(line, key);
encrypt(key);
}
void gridStr(char *line, char *key)
{
char mat[10][10] = {0};
int columns = strlen(key)-1;
int rows = 0;
int i=0,j = 0;
while (line[i]) {
if (line[i] == ' ') {
putchar('_');
} else {
putchar(line[i]);
}
mat[rows][i % columns] = line[i];
i++;
if (i > 0 && i % columns == 0) {
putchar('\n');
rows++;
}
}
if (i % columns != 0) putchar('\n');
rows++; // from current row to number of rows
printf("\nMatrix:\n");
for (i = 0; i < rows; i++) {
for (j = 0; j < columns; j++) {
if (mat[i][j] == ' ') {
putchar('_');
} else {
putchar(mat[i][j]);
}
}
printf("\n");
}
}
char encrypt(char *key){
char temp;
int i,j;
int n = strlen(key);
for (i = 0; i < n-1; i++) {
for (j = i+1; j < n; j++) {
if (key[i] > key[j]) {
temp = key[i];
key[i] = key[j];
key[j] = temp;
}
}
}
printf("The sorted string is : %s", key);
return 0;
}

You do not want to swap the columns each time a bubble moves in the sorting algorithm until it reaches its final position. Therefore, the sorting can be performed separately.
Determining which columns to swap is implemented in the following way:
Iterate over all columns from start to end
If a column has not been swapped, find its counterpart and swap them
Mark both swapped columns in order to not swap them again, continue iteration
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
// use bubble sort to sort letters in a string
void sort_letters(char *phrase) {
int n = strlen(phrase);
//printf("The string to sort is: %s\n", phrase);
for (int i = 0; i < n-1; i++) {
for (int j = i+1; j < n; j++) {
if (phrase[i] > phrase[j]) {
char temp = phrase[i];
phrase[i] = phrase[j];
phrase[j] = temp;
}
}
}
//printf("The sorted string is: %s\n", phrase);
}
// allocate a matrix for string and fill it
char** gridStr(char *line, char *key)
{
int n = strlen(line);
int columns = strlen(key);
int rows = (n + columns - 1) / columns;
char **matrix = malloc(rows * sizeof(char *));
for (int j = 0; j < rows; j++) {
matrix[j] = malloc(columns * sizeof(char));
}
int i = 0;
for (int k = 0; k < rows; k++) {
for (int l = 0; l < columns; l++) {
if (i<n) {
matrix[k][l] = line[i++];
} else {
matrix[k][l] = '*'; // fill letter
}
//putchar(matrix[k][l]);
}
//putchar('\n');
}
return matrix;
}
// swap columns i and j of the given matrix, zero-based indices
void swap_matrix_columns(char **matrix, int rows, int columns, int i, int j) {
for (int k = 0; k < rows; k++) {
char tmp = matrix[k][i];
matrix[k][i] = matrix[k][j];
matrix[k][j] = tmp;
}
}
// print matrix to stdout
void print_matrix(char **matrix, int rows, int columns) {
for (int i = 0; i < rows; i++){
printf("Row %2d: ", i);
for (int j = 0; j < columns; j++) {
putchar(matrix[i][j]);
}
putchar('\n');
}
}
// sort key and transpose matrox columns according new order
void encrypt(char **matrix, int rows, int columns, char *key) {
char sorted_key[strlen(key)];
strcpy(sorted_key, key);
sort_letters(sorted_key);
printf("Sorted key: %s (length: %2zu)\n", sorted_key, strlen(sorted_key));
bool is_used[columns];
for (int i = 0; i < columns; i++) is_used[i]= false;
for (int i = 0; i < columns; i++) {
if (!is_used[i]) {
// find new position, must exist
int j;
for (j = 0; j < columns; j++) {
if (key[i] == sorted_key[j] && !is_used[j]) {
break;
}
}
swap_matrix_columns(matrix, rows, columns, i, j);
is_used[i] = true;
is_used[j] = true;
}
}
}
int main(void) {
char key[50];
char line[256];
printf("Enter your string: ");
if (fgets(line, sizeof line, stdin) == NULL) {
fprintf(stderr, "No line read\n");
exit(EXIT_FAILURE);
}
printf("Enter your key: ");
if (fgets(key, sizeof key, stdin) == NULL) {
fprintf(stderr, "No line read\n");
exit(EXIT_FAILURE);
}
int len = strlen(line);
if (len && line[len - 1] == '\n') {
line[--len] = '\0';
}
int len1 = strlen(key);
if (len1 && key[len1 - 1] == '\n') {
key[--len1]= '\0';
}
//printf("string: |%s| (length: %2zu)\n", line, strlen(line));
//printf("key: |%s| (length: %2zu)\n", key, strlen(key));
char **matrix = gridStr(line, key);
int columns = len1;
// Use simple trick (+ len1 - 1) to determine number of rows with one integer divison
int rows = (len + columns - 1) / columns;
print_matrix(matrix, rows, columns);
encrypt(matrix, rows, columns, key);
print_matrix(matrix, rows, columns);
for (int row = 0; row < rows; row++) {
free(matrix[row]);
}
free(matrix);
return EXIT_SUCCESS;
}
$ gcc -Wall transposition.c
$ ./a.out
Enter your string: hello_there
Enter your key: KEY
Row 0: hel
Row 1: lo_
Row 2: the
Row 3: re*
Sorted key: EKY (length: 3)
Row 0: ehl
Row 1: ol_
Row 2: hte
Row 3: er*
$

You have a 2D array. The first axis is the list of strings. The second axis is the characters of a particular string. I assume when you mean swap column, you mean swap characters of a particular string for all strings.
In pseudo code:
for all strings i
temp = mat[i][some column]
mat[i][some column] = mat[i][someother column]
mat[i][someother column] = temp

Related

C program to compare each word of a 2D array to all words of the order 2D array

I created 2 2D arrays containing words. For example:
loadKey[25][30] =
{
{'J','a','v','a','\0'},
{'P','y','t','h','o','n','\0'},
{'C','+','+','\0'},
{'H','T','M','L','\0'},
{'S','Q','L','\0'}
// ... 20 other words here
};
resume[189][30] =
{
{'L','a','l','a','\0'},
{'H','i','h','i','h','i','\0'},
{'C','+','+','\0'},
{'Y','o','Y','o','\0'},
{'S','Q','L','\0'}
// ... 184 other words here
};
I would like to compare each word of a loadKey[] to all words of resume[] to count how many times 25 words of loadKey[] matched of words of resume[]. I tried the strcmp(loadKey[i], resume[j]) but it's pointer of array.
Anyone can help me to solve this problem? Thanks so much!
My program code:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PAUSE myPause()
#define KEYWORD 25
#define WORDS 250
#define MAX_LETTER 30
//*********************************************
// FUNCTION PROTOTYPES
void compAndCount(char loadKey[][MAX_LETTER], char resume[][MAX_LETTER]);
void myPause();
void readAndLoadKeyword(char loadKey[][MAX_LETTER]);
// MAIN FUNCTION
int main() {
char loadKey[KEYWORD][MAX_LETTER];
char resume[WORDS][MAX_LETTER];
// load keywords from keywords file into array loadKey[]
readAndLoadKeyword(loadKey);
for (int j = 0; j < KEYWORD; j++)
{
puts(loadKey[j]);
}
puts("\n");
// compare and count the occurrences of keyword in resumes file
compAndCount(loadKey, resume);
}
// FUNTIONS
void compAndCount(char loadKey[][MAX_LETTER], char resume[][MAX_LETTER]) {
FILE* fpr;
fpr = fopen("resumes.txt", "r");
int r = 0, count = 0, num = 0, res = 0;
char temp;
while ((temp = fgetc(fpr)) != EOF) {
if (temp != ' ' && temp != '\n') {
resume[res][r] = temp;
r++;
}
else
{
resume[res][r] = '\0';
r = 0;
res++;
}
}
printf("words in resume file %i\n", res);
for (int j = 0; j < res; j++)
{
puts(resume[j]);
}
puts("\n");
/*
// way 1 to compare and count (WRONG?)
for (int i = 0; i < res; i++) {
if (i < KEYWORD) {
scanf(" %[^\n]", loadKey[i]);
}
scanf(" %[^\n]", resume[i]);
}
for (int k = 0; k < KEYWORD; k++) {
for (int l = 0; l < res; l++) {
if (strcmp(loadKey[k], resume[l]) == 0)
count++;
}
}*/
/*
// way 2 to compare and count (WRONG?)
char key[MAX_LETTER] = {'\0'}, r[MAX_LETTER] = {'\0'};
for (int i = 0; i < KEYWORD; i++) {
strcpy(key, loadKey[i]);
for (int l = 0; l < res; l++) {
strcpy(r, resume[l]);
if (strcmp(key, r) == 0)
count++;
}
}
*/
printf("Resume Rating: %i\n", count);
fclose(fpr);
} // end compAndCount
void myPause() {
puts("\nPress ENTER to continue\n");
exit(0);
}
void readAndLoadKeyword(char loadKey[][MAX_LETTER]) {
FILE* fp;
fp = fopen("keywords.txt", "r");
char ch;
int row = 0, col = 0;
if (fp == NULL) {
puts("Not able to open keyword file!");
PAUSE;
}
// load 25 keywords and ',' into an array line[]
char line[181]; // 180 characters + '\0'
fgets(line, 181, fp);
puts(line);
puts("\n");
// load 25 words in array line[] into array loadKey[]
for (int i = 0; i < 180; i++) {
ch = line[i];
if (ch != ',') {
loadKey[row][col] = ch;
col++;
}
else {
loadKey[row][col] = '\0';
col = 0;
row++;
}
}
fclose(fp);
} // end readAndLoadKeyword
You can use string literals instead of {} of chars
Arrays can have a different number of columns and rows.
char loadKey[25][30] =
{
"Java",
"Python",
// ... more words here
};
char resume[189][30] =
{
"Lala",
"Hihihi",
"C++",
// more
};
//lkr - number of loadKer rows
//lkr - number of loadKer columns
//rr - number of resume rows
//rc - number of resume columns
//rep - count duplicates
size_t count(size_t lkr, size_t lkc, size_t rr, size_t rc, char (*loadKey)[lkc], char (*resume)[rc], int rep)
{
size_t result = 0;
for(size_t lkrow = 0; lkrow < lkr; lkrow++)
{
for(size_t rrow = 0; rrow < rr; lrow++)
{
if(!strcmp(loadKey[lkrow], resume[rrow]))
{
result++;
if(!rep) break;
}
}
}
return result;
}
If the same string can be present in the resume array more than once and oyu want to count duplicates as well rep parameter should be non-zero.
Example usage:
int main(void)
{
size_t cnt = count(25, 30, 189, 30, loadKey, resume, 0);
printf("%zu\n", count);
}

How do i create a "matrix" with words in C

The problem is the following:
Have to check if the words in the matrix are palindromes or not. Have to read the words as well.
My main problem is introducing the words because until now I could only do a function reading the first letter, not the whole word.
After that, I think that I can check alone if it is a palindrome or not.
This is an example of data:
mat←["ac" "lup" ]
["ou" "lupul"]
["ABBA" "greu" ]
m←3 number of rows
n←2 number of columns
This what I wrote until now:
A function where you introduce the words:
char** read(int *m ,int *n)
{
printf("No of lines=");
scanf("%d",m);
printf("No of columns=");
scanf("%d",n);
char **a=(char**)malloc(*m*sizeof(char*));
for (int i=0;i<*m;i++)
{
a[i]=(char*)malloc(*n*sizeof(char));
for (int j=0; j<*n; j++)
{
fflush(stdin);
printf("Element [%d][%d]=",i,j);
gets(a[i]+j); // <=> &a[i][j]
}
}
return a;
}
Another one which displays it:
void display(char **x, int m, int n)
{
for (int i=0; i<m; i++)
{
for (int j=0; j<n; j++)
printf("%c ",x[i][j]);
printf("\n");
}
}
Another one which deletes the data:
void freematrix(char **x, int m)
{
for (int i=0; i<m; i++)
free(x[i]);
free(x);
}
This is the main part:
int main()
{
int m, n;
char **mat;
mat=read(&m,&n);
display(mat,m,n);
freematrix(mat,m);
return 0;
}
Try this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_ROWS 8 // to limit the usecase
#define MAX_COLS 8
#define MAX_MAT_STR_LEN 15 //
char* str_dupe (const char* str, const int max_slen)
{
if (!str || max_slen < 1) return NULL;
char* dupe = malloc (max_slen + 1);
if (!dupe) {
perror("\nERROR: str_dupe-malloc");
return NULL;
}
dupe[max_slen] = '\0'; // guard
for (int ci =0; ci < max_slen; ++ci) {
dupe[ci] = str[ci];
if ('\0' == dupe[ci])
break; // stop copying
}
return dupe;
}
void free_strMatrix (char ***sm, const int rows, const int cols)
{
if (!sm || rows < 1 || cols < 1) return;
for (int ri = 0; ri < rows; ++ri) {
if (sm[ri]) {
for (int ci = 0; ci < cols; ++ci) {
if (sm[ri][ci]) { // check if it's NULL
free (sm[ri][ci]);
sm[ri][ci] = NULL; //prevent dangling pointers
}
}
free (sm[ri]); // row of string pointers
sm[ri] = NULL; // good practice
}
}
free (sm);
}
char*** read_strMatrix (int *rows, int *cols)
{
while (1) {
printf ("\nChoose Rows [1..%d]: ", MAX_ROWS);
if (1 == scanf("%d", rows) && *rows > 0 && *rows <= MAX_ROWS)
break;
else
printf ("\nERROR: Invalid Row-Count. Try Again!");
}
while (1) {
printf ("\nChoose Columns [1..%d]: ", MAX_COLS);
if (1 == scanf("%d", cols) && *cols > 0 && *cols <= MAX_COLS)
break;
else
printf ("\nERROR: Invalid Column-Count. Try Again!");
}
char*** sm = (char***) calloc ((*rows), sizeof (char**));
if (NULL == sm) {
perror("read_strMatrix-malloc-1");
return NULL;
}
for (int ri = 0; ri < *rows; ++ri) {
sm[ri] = (char**) calloc ((*cols), sizeof (char*));
if (NULL == sm[ri]) {
perror ("read_strMatrix-malloc-2");
//ideally you should free allocated memory before return
free_strMatrix(sm, *rows, *cols);
return NULL;
}
}
char str[256]; //interim string buffer;
for (int ri = 0; ri < *rows; ++ri) {
for (int ci=0; ci < *cols; ++ci ) {
printf ("String for strMatrix[%d][%d] : ", ri, ci);
// strings more than 255 chars will be split ; so be within limit duing input
while (1 != scanf ("%255s", str));
// only copying MAX_MAT_STR_LEN chars
sm[ri][ci] = str_dupe (str, MAX_MAT_STR_LEN);
if (NULL == sm[ri][ci]) {
perror("read_strMatrix-strndup");
//ideally you should free allocated memory before return
free_strMatrix (sm, *rows, *cols);
return NULL;
}
}
printf ("\n");
}
return sm;
}
void disp_strMatrix (char ***sm, const int rows, const int cols)
{
if (!sm || rows < 1 || cols < 1) return;
printf ("\nStringMatrix [%d][%d]:\n", rows, cols);
for (int ri = 0; ri < rows; ++ri) {
if (sm[ri]) {
for (int ci = 0; ci < cols; ++ci)
printf ("%s\t", sm[ri][ci]);
}
printf ("\n");
}
printf ("\n");
}
int main()
{
int rows, cols;
char ***strMatrix;
strMatrix = read_strMatrix (&rows, &cols);
if (!strMatrix) {
printf ("\nERROR: reading strMatrix\n");
return 1;
}
disp_strMatrix (strMatrix, rows, cols);
free_strMatrix (strMatrix, rows, cols);
strMatrix = NULL; // good practice
return 0;
}
You can also prepare an input.txt file like:
3 4
aaaaa sssss ffg gggg
hhhh jj kkkkkk lllll
qqq wwwww eeeee rrrrr
On Linux you can run the program like:
./a.out < input.txt

I wrote a code to print the union and intersection of two strings sets. I allocated memory in some parts.The last part is not working properly

The last part of the code where I am allocating memory to common_set is not working whereas other mallocs worked fine above. Similarly when I freed the unique_set for the third time it is not done properly. I am not able to get the printf sentences which I wrote after them. I am not able to free the pointer of the union_set. Also I am not able to allocate memory to a new pointer common_pointer.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
void dict(char **str, int man, int MAY) {
char temp[MAY];
for (int i = 0; i < man; ++i) {
for (int j = i + 1; j < man; ++j) {
if (strcmp(str[i], str[j]) > 0) {
strcpy(temp, str[i]);
strcpy(str[i], str[j]);
strcpy(str[j], temp);
}
}
}
}
//int k = 0;
char **unique_set;
char **a_new_sumset;
int unique(char **s, int l, int d, int k) {
if (d == l) {
unique_set[k] = (char*)malloc((strlen(s[l]) + 1) * sizeof(char));
strcpy(unique_set[k], s[l]);
return k;
} else {
for (int i = l; i < d; i++) {
if (strcmp(s[i], s[i + 1]) == 0 && i + 1 == d) {
unique_set[k] = (char*)malloc((strlen(s[i + 1]) + 1) * sizeof(char));
strcpy(unique_set[k], s[i + 1]);
return k;
//printf("demo: %s\n", unique_set[k]);
} else
if (strcmp(s[i], s[i + 1]) != 0) {
unique_set[k] = (char*)malloc((strlen(s[i]) + 1) * sizeof(char));
strcpy(unique_set[k], s[i]);
//printf("demo1: %s\n", unique_set[k]);
k++;
unique(s, i + 1, d, k);
break;
}
}
}
}
char **common_set;
char **intersection(char **sum_set, int d) {
int k = 0;
for (int i = 0; i < d; i++) {
if (strcmp(sum_set[i], sum_set[i + 1]) == 0 && strcmp(sum_set[i], sum_set[i + 2]) != 0 && i + 2 < d) {
common_set[k] = (char*)malloc((strlen(sum_set[i]) + 1) * sizeof(char));
strcpy(common_set[k], sum_set[i]);
k++;
} else
if (strcmp(sum_set[i], sum_set[i + 1]) == 0 && i + 2 > d) {
common_set[k] = (char*)malloc((strlen(sum_set[i]) + 1) * sizeof(char));
strcpy(common_set[k], sum_set[i]);
k++;
}
}
return common_set;
}
#define maxx1 3 // number of words in grp 1
#define maxy1 10 // word limit for the first group of words
#define maxx2 3 // number of words in grp2
#define maxy2 10 // word limit for the next group of words
int main() {
char **sum_set;
char **str_g1;
char **str_g2;
char words1[maxy1];
str_g1 = (char**)malloc(maxx1 * sizeof(char*));
char words2[maxy2];
str_g2 = (char**)malloc(maxx2 * sizeof(char*));
printf("Enter the first group:\n");
for (int i = 0; i < maxx1; i++) {
gets(words1);
str_g1[i] = (char*)malloc((strlen(words1) + 1) * sizeof(char));
strcpy(str_g1[i], words1);
//puts(ptr[i]);
//printf("%d", i);
}
printf("Enter the second group:\n");
for (int i = 0; i < maxx2; i++) {
gets(words2);
str_g2[i] = (char*)malloc((strlen(words2) + 1) * sizeof(char));
strcpy(str_g2[i], words2);
//puts(ptr[i]);
//printf("%d", i);
}
dict(str_g1, maxx1, maxy1); //to lexicographically arrange the string 1 group
dict(str_g2, maxx2, maxy2);
sum_set = (char**)malloc((maxx1 + maxx2) * sizeof(char*));
a_new_sumset = (char**)malloc((maxx1 + maxx2) * sizeof(char*));
for (int i = 0; i < maxx1; i++) {
sum_set[i] = (char*)malloc((strlen(str_g1[i]) + 1) * sizeof(char));
strcpy(sum_set[i], str_g1[i]);
//puts(sum_set[i]);
}
for (int i = 0; i < maxx2; i++) {
sum_set[i + maxx1] = (char*)malloc((strlen(str_g2[i]) + 1) * sizeof(char));
strcpy(sum_set[i + maxx2], str_g2[i]);
//puts(sum_set[i + maxx1]);
}
dict(sum_set, maxx1 + maxx2, maxy1 + maxy2);
unique_set = (char**)malloc((maxx1) * sizeof(char*));//allocating memory to next string group to compute its set
int k = unique(str_g1, 0, maxx1 - 1, 0);
printf("%d \n", k);
printf("The set of the string A in arranged order is:\n");
for (int i = 0; i <= k; i++) {
a_new_sumset[i] = (char*)malloc((strlen(unique_set[i]) + 1) * sizeof(char));
strcpy(a_new_sumset[i], unique_set[i]);
puts(unique_set[i]);
//
}
//printf("freed the pointers\n");
for (int i = 0; i <= k; ++i) {//freeing the arrays
free(unique_set[i]);
}
free(unique_set);
//printf("freed the pointers\n");//freeing the top pointer
int a = k;
unique_set = (char**)malloc((maxx2) * sizeof(char*));//allocating memory to next string group to compute its set
k = unique(str_g2, 0, maxx2 - 1, 0);
int b = k;
printf("The set of the string B in arranged order is:\n");
for (int i = 0; i <= k; i++) {
a_new_sumset[i + 1 + a] = (char*)malloc((strlen(unique_set[i]) + 1) * sizeof(char));
strcpy(a_new_sumset[i + a + 1], unique_set[i]);
puts(unique_set[i]);
//strcpy(a_new_sumset[i + a + 1], unique_set[i]);
}
printf("%d \n", k);
for (int i = 0; i <= k; ++i) {//freeing the arrays
free(unique_set[i]);
}
free(unique_set);//freeing the top pointer
printf("freed the pointers\n");
unique_set = (char**)malloc((a + b) * sizeof(char*));//allocating memory to unique_set for computing the union of the sets
k = unique(sum_set, 0, (maxx1 + maxx2) - 1, 0);
printf("The set of the string A+B in arranged order is:\n");
for (int i = 0; i <= k; i++)
puts(unique_set[i]);
for (int i = 0; i <= k; ++i) {//freeing the arrays
free(unique_set[i]);
}
printf("freed the pointers\n");
free(unique_set);
printf("freed the pointers\n");
printf("The intersection_set of the string A+B in arranged order is:\n");
common_set = (char**)malloc((maxx1 + maxx2) * sizeof(char*));
printf("The intersection_set of the string A+B in arranged order is:\n");
char **p;
p = intersection(a_new_sumset, (maxx1 + maxx2) - 1);
printf("The intersection_set of the string A+B in arranged order is:\n");
for (int i = 0; i <maxx1 + maxx2; i++) {
puts(p[i]);
}
}
There are many issues in the code:
in function dict, you should not copy the strings, but swap the pointers instead, which is simpler and works for any string length. Furthermore the name dict is confusing for this function, prefer a more informative name such as sort_strings:
void sort_strings(char **str, int man) {
for (int i = 0; i < man; ++i) {
for (int j = i + 1; j < man; ++j) {
if (strcmp(str[i], str[j]) > 0) {
char *temp = str[i];
str[i] = str[j];
str[j] = temp;
}
}
}
}
global variables are not necessary for this task, prefer local variables, pass destination arrays as arguments and return the number of strings as the return value.
the string allocation code is duplicated everywhere... using the strdup() function or a wrapper that tests for memory allocation failure would improve readability.
avoid variable name l, which looks confusingly similar to 1
the uniq function does not return a value in the else branch, it is unclear what it does and why it is recursive.
the loop to add the strings from the second group has a bug: strcpy(sum_set[i + maxx2], str_g2[i]); should be strcpy(sum_set[i + maxx1], str_g2[i]);. This mistake has no effect now because maxx1 == maxx2 but should be fixed.
in function intersection, you compare strings at offset d + 1 and d + 2 before testing if these index values are within the array boundaries.
selecting duplicated strings in intersection makes the assumption that strings are not duplicated in group 1 and 2.
the number of common strings is not returned, nor stored into a global variable, so main() cannot determine this number and uses maxx1 + maxx2 which is always wrong for non trivial cases.
Here is a modified version using functions to read lines, sort an array, find unique values, compute the union and intersection of sets and free the string arrays:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// allocate a copy of a string or die
char *xstrdup(const char *str) {
char *p = strdup(str);
if (p == NULL) {
fprintf(stderr, "out of memory\n");
exit(1);
}
return p;
}
// read a line of at most max bytes
char *get_line(int max) {
char buf[max + 1];
int i = 0;
int c;
while ((c = getchar()) != EOF && c != '\n') {
if (i < max) {
buf[i++] = (char)c;
}
}
buf[i] = '\0';
return xstrdup(buf);
}
// free the strings in an array of size n
void free_strings(char **strings, int n) {
for (int i = 0; i < n; i++) {
free(strings[i]);
}
}
// copy strings in lexicographical order
int sort_strings(char **sorted, char **str, int n) {
int i, j;
for (i = 0; i < n; i++) {
for (j = i; j > 0 && strcmp(sorted[j - 1], str[i]) > 0; j--) {
sorted[j] = sorted[j - 1];
}
sorted[j] = xstrdup(str[i]);
}
return n;
}
// copy unique strings in lexicographical order
int uniq_strings(char **unique_strings, char **strings, int n) {
int i, k = 0;
for (i = 0; i < n; i++) {
if (i == 0 || strcmp(strings[i - 1], strings[i]) != 0) {
unique_strings[k++] = xstrdup(strings[i]);
}
}
return k;
}
int intersection_strings(char **intersection_set, char **str1, int n1, char **str2, int n2) {
int i = 0, j = 0, k = 0;
while (i < n1 && j < n2) {
int c = strcmp(str1[i], str2[j]);
if (c < 0) {
i++;
} else
if (c > 0) {
j++;
} else {
intersection_set[k++] = xstrdup(str1[i]);
i++;
j++;
}
}
return k;
}
int union_strings(char **union_set, char **str1, int n1, char **str2, int n2) {
int i = 0, j = 0, k = 0;
while (i < n1 && j < n2) {
int c = strcmp(str1[i], str2[j]);
if (c < 0) {
union_set[k++] = xstrdup(str1[i]);
i++;
} else
if (c > 0) {
union_set[k++] = xstrdup(str2[j]);
j++;
} else {
union_set[k++] = xstrdup(str1[i]);
i++;
j++;
}
}
while (i < n1) {
union_set[k++] = xstrdup(str1[i++]);
}
while (j < n2) {
union_set[k++] = xstrdup(str2[j++]);
}
return k;
}
void print_set(char **set, int n, const char *desc) {
if (desc) {
printf("%s", desc);
}
for (int i = 0; i < n; i++) {
puts(set[i]);
}
}
#define maxx1 3 // number of words in grp 1
#define maxy1 10 // word limit for the first group of words
#define maxx2 3 // number of words in grp2
#define maxy2 10 // word limit for the second group of words
int main() {
char *str_g1[maxx1];
char *str_s1[maxx1];
char *str_u1[maxx1];
char *str_g2[maxx2];
char *str_s2[maxx2];
char *str_u2[maxx2];
char *union_set[maxx1 + maxx2];
char *intersection_set[maxx1 < maxx2 ? maxx1 : maxx2];
printf("Enter the first group:\n");
for (int i = 0; i < maxx1; i++) {
str_g1[i] = get_line(maxy1);
}
printf("Enter the second group:\n");
for (int i = 0; i < maxx2; i++) {
str_g2[i] = get_line(maxy2);
}
sort_strings(str_s1, str_g1, maxx1);
int n1 = uniq_strings(str_u1, str_s1, maxx1);
sort_strings(str_s2, str_g2, maxx1);
int n2 = uniq_strings(str_u2, str_s2, maxx2);
print_set(str_u1, n1, "The set of the string A in arranged order is:\n");
print_set(str_u2, n2, "The set of the string B in arranged order is:\n");
// compute union and intersection
int nu = union_strings(union_set, str_u1, n1, str_u2, n2);
int ni = intersection_strings(intersection_set, str_u1, n1, str_u2, n2);
print_set(union_set, nu, "The set of the string A+B in arranged order is:\n");
print_set(intersection_set, ni, "The intersection_set of the string A*B in arranged order is:\n");
free_strings(str_g1, maxx1);
free_strings(str_g2, maxx2);
free_strings(str_s1, maxx1);
free_strings(str_s2, maxx2);
free_strings(str_u1, n1);
free_strings(str_u2, n2);
free_strings(union_set, nu);
free_strings(intersection_set, ni);
return 0;
}
To improve on this code, you can define a structure string_set to combine the string array along with variables describing its allocated size and active count. Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct string_set {
int count, size;
char **array;
} string_set;
// allocate a copy of a string or die
char *xstrdup(const char *str) {
char *p = strdup(str);
if (p == NULL) {
fprintf(stderr, "out of memory\n");
exit(1);
}
return p;
}
void *xalloc(size_t n) {
void *p = malloc(n);
if (p == NULL) {
fprintf(stderr, "out of memory\n");
exit(1);
}
return p;
}
string_set *string_set_allocate(int size) {
string_set *set = xalloc(sizeof(*set));
set->count = 0;
set->size = size;
set->array = xalloc(sizeof(*set->array) * size);
return set;
}
void string_set_free(string_set *set) {
while (set->count --> 0) {
free(set->array[set->count]);
}
free(set->array);
free(set);
}
// read a line of at most max bytes
char *get_line(int max) {
char buf[max + 1];
int i = 0;
int c;
while ((c = getchar()) != EOF && c != '\n') {
if (i < max) {
buf[i++] = (char)c;
}
}
buf[i] = '\0';
return xstrdup(buf);
}
string_set *string_set_clone(string_set *set) {
string_set *copy = string_set_allocate(set->size);
for (int i = 0; i < set->count; i++) {
copy->array[i] = xstrdup(set->array[i]);
}
copy->count = set->count;
return copy;
}
void string_set_sort(string_set *set) {
for (int i = 0; i < set->count; i++) {
for (int j = i + 1; j < set->count; j++) {
if (strcmp(set->array[i], set->array[j]) > 0) {
char *temp = set->array[i];
set->array[i] = set->array[j];
set->array[j] = temp;
}
}
}
}
void string_set_uniq(string_set *set) {
if (set->count > 0) {
int j = 1;
for (int i = 1; i < set->count; i++) {
if (strcmp(set->array[i], set->array[j - 1]) == 0) {
free(set->array[i]);
set->array[i] = NULL;
} else {
set->array[j++] = set->array[i];
}
}
set->count = j;
}
}
string_set *string_set_intersection(string_set *set1, string_set *set2) {
int n1 = set1->count;
int n2 = set2->count;
string_set *res = string_set_allocate(n1 < n2 ? n1 : n2);
int i = 0, j = 0, k = 0;
while (i < n1 && j < n2) {
int c = strcmp(set1->array[i], set2->array[j]);
if (c < 0) {
i++;
} else
if (c > 0) {
j++;
} else {
res->array[k++] = xstrdup(set1->array[i]);
i++;
j++;
}
}
res->count = k;
return res;
}
string_set *string_set_union(string_set *set1, string_set *set2) {
int n1 = set1->count;
int n2 = set2->count;
string_set *res = string_set_allocate(n1 + n2);
int i = 0, j = 0, k = 0;
while (i < n1 && j < n2) {
int c = strcmp(set1->array[i], set2->array[j]);
if (c < 0) {
res->array[k++] = xstrdup(set1->array[i]);
i++;
} else
if (c > 0) {
res->array[k++] = xstrdup(set2->array[j]);
j++;
} else {
res->array[k++] = xstrdup(set1->array[i]);
i++;
j++;
}
}
while (i < n1) {
res->array[k++] = xstrdup(set1->array[i++]);
}
while (j < n2) {
res->array[k++] = xstrdup(set2->array[j++]);
}
res->count = k;
return res;
}
void string_set_print(string_set *set, const char *desc) {
if (desc) {
printf("%s", desc);
}
for (int i = 0; i < set->count; i++) {
puts(set->array[i]);
}
}
#define maxx1 3 // number of words in grp 1
#define maxy1 10 // word limit for the first group of words
#define maxx2 3 // number of words in grp2
#define maxy2 10 // word limit for the second group of words
int main() {
string_set *str_g1 = string_set_allocate(maxx1);
string_set *str_g2 = string_set_allocate(maxx2);
printf("Enter the first group:\n");
for (int i = 0; i < maxx1; i++) {
str_g1->array[str_g1->count++] = get_line(maxy1);
}
printf("Enter the second group:\n");
for (int i = 0; i < maxx2; i++) {
str_g2->array[str_g2->count++] = get_line(maxy2);
}
string_set *str_u1 = string_set_clone(str_g1);
string_set_sort(str_u1);
string_set_uniq(str_u1);
string_set *str_u2 = string_set_clone(str_g2);
string_set_sort(str_u2);
string_set_uniq(str_u2);
string_set_print(str_u1, "The set of the string A in arranged order is:\n");
string_set_print(str_u2, "The set of the string B in arranged order is:\n");
string_set *union_set = string_set_union(str_u1, str_u2);
string_set *intersection_set = string_set_intersection(str_u1, str_u2);
string_set_print(union_set, "The set of the string A+B in arranged order is:\n");
string_set_print(intersection_set, "The intersection set of the string A*B in arranged order is:\n");
string_set_free(str_g1);
string_set_free(str_g2);
string_set_free(str_u1);
string_set_free(str_u2);
string_set_free(union_set);
string_set_free(intersection_set);
return 0;
}
The last part of the code where I am allocating memory to common_set is not working ...
The problem in this part is not the allocation, but the implementation of the intersection function. You haven't provided a means for this function to return the number of elements in the intersection set, and you haven't initialized the allocated set space - you just try to access maxx1 + maxx2 set elements, most of which are undefined. Fixing this design would be a start.

Checking if an array contains all the elements

I wrote a Code that reads from a txt.file stores it into an array , remove the spaces then print them out.
I want to add another functionality. This time is to check if the user provided the right input file.
I want to compare the array reds with the array stringcard and see if the array red contains all the elements of the array stringcard.
I have been searching on the internet for a while but I don't know how to solve this problem.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define max 13
#define stringlength 8
const char *stringcard[] = {
"REDA",
"RED2",
"RED3",
"RED4",
"RED5",
"RED6",
"RED7",
"RED8",
"RED9",
"RED10",
"REDJ",
"REDQ",
"REDK",
};
char * removechar(char str[], int ch) {
char * cpos = str;
while ((cpos = strchr(cpos, ch))) {
strcpy(cpos, cpos + 1);
}
return str;
}
int main(int argc, char ** argv) {
char * reds[max];
int i;
FILE * file = argc > 1 ? fopen(argv[1], "r") : stdin;
if (file == NULL)
return 1;
if (argc != 2) {
printf("[ERR]");
return 0;
}
for (i = 0; i < max; i++) {
reds[i] = malloc(stringlength);
fgets(reds[i], stringlength, file);
}
for (i = 0; i < max; i++) {
printf("%s", reds[i]);
}
// removes spaces
for (i = 0; i < max; i++) {
removechar(reds[i], ' ');
}
for (i = 0; i < max; i++) {
printf("%s", reds[i]);
}
int success = 1;
size_t size = sizeof(stringcard)/sizeof(stringcard[0]);
size_t size2 = sizeof(reds)/sizeof(reds[0]);
if(size == size2)
{
for(int i = 0; i<size;i++)
{
if(strcmp(stringcard[i], reds[i]) != 0){
success = 0;
printf("nope");
break;
}
}
}
return 0;
}
Input:
RED A
RED 2
RED 3
RED 4
RED 5
RED 6
RED 7
RED 8
RED 9
RED 10
RED J
RED Q
RED K
This is prefaced by my top comments.
This should work for cards in any order:
size_t size = sizeof(stringcard) / sizeof(stringcard[0]);
size_t size2 = sizeof(reds) / sizeof(reds[0]);
int allmatch = 0;
if (size == size2) {
allmatch = 1;
for (int i = 0; i < size; ++i) {
int curmatch = 0;
const char *curcard = &stringcard[i];
for (int j = 0; j < size; ++j) {
if (strcmp(curcard, reds[j]) == 0) {
curmatch = 1;
break;
}
}
if (! curmatch) {
allmatch = 0;
break;
}
}
}
printf("RESULT: %s\n",allmatch ? "MATCH" : "NOMATCH");
UPDATE:
if we know reds is sorted compare the result of strcmp with -1 or 1 rather than 0 depending on the order of the sorted elements. If stringcard is sorted of course exchange the roles
Okay, if we assume stringcard is always sorted [or we choose to pre-sort it], we can add an early escape to the inner loop that can save a small amount of time for the failed case:
size_t size = sizeof(stringcard) / sizeof(stringcard[0]);
size_t size2 = sizeof(reds) / sizeof(reds[0]);
int allmatch = 0;
if (size == size2) {
allmatch = 1;
for (int i = 0; i < size; ++i) {
int curmatch = 0;
char *redcard = reds[i];
for (int j = 0; j < size; ++j) {
int cmpflg = strcmp(redcard,stringcard[j]);
if (cmpflg == 0) {
curmatch = 1;
break;
}
if (cmpflg > 0)
break;
}
if (! curmatch) {
allmatch = 0;
break;
}
}
}
printf("RESULT: %s\n",allmatch ? "MATCH" : "NOMATCH");
Always try to use functions when possible.
int all_match(const char **table1, const char **table2, size_t t1size, size_t t2size)
{
for(size_t t1index = 0; t1index < t1size; t1index++)
{
int match = 0;
for(size_t t2index = 0; t2index < t2size; t2index++)
{
match = match || !strcmp(table1[t1index], table2[t2index]);
if(match) break;
}
if(!match) return 0;
}
return 1;
}
Given your other array is defined similarly, say inputArray, and both arrays are sorted before executing the following, then you could use code similar to: (including number of elements
//Assumes both arrays are sorted before executing the following
char success = 1;
size_t size = sizeof(stringcard)/sizeof(stringcard[0]);
size_t size2 = sizeof(inputArray)/sizeof(inputArray[0]);
if(size == size2)
{
for(int i = 0; i<size;i++)
{
if(strcmp(stringcard[i], inputArray[i]) != 0)
{
success = 0;
break;
}
}
{
else
{
success = 0;
}
//Proceed according to the value of success,
...

How can I get the proper dimensions of unknown matrixes for a matrix multiplier C program?

So my attempt was that creating a program that automatically gets two matrixes' size from a .txt file and multiplies them. I could make the program with given sizes so in itself I only have problem with counting the cols and rows.
The input something like (MxN matrix):
1 2 3 4
1 2 3 4
1 2 3 4
To be specific, here is my program so far (the beginning of the code is relevant I think):
#include <stdio.h>
#include <stdlib.h>
struct mat1
{
int cols;
int rows;
};
struct mat2
{
int cols;
int rows;
};
struct mat1 dim1(const char* file)
{
struct mat1 m1;
int rows = 0;
int cols = 0;
char c;
FILE *f = fopen(file, "r+");
while((c = fgetc(f) != EOF))
{
if(c != '\n' && rows == 0)
{
cols++;
}
else if(c == '\n')
rows++;
}
rows++;
return m1;
}
struct mat2 dim2(const char* file)
{
struct mat2 m2;
int rows = 0;
int cols = 0;
char c;
FILE *f = fopen(file, "r+");
while((c = fgetc(f) != EOF))
{
if(c != '\n' && rows == 0)
{
cols++;
}
else if(c == '\n')
rows++;
}
rows++;
return m2;
}
double* alloc_matrix(int cols, int rows) {
double* m = (double*)malloc(cols * rows * sizeof(double));
if (m == 0) {
printf("Memory allocation error.\n");
exit(-1);
}
return m;
}
void read_matrix(FILE* f, double* m, int cols, int rows) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
fscanf(f, "%lf", &m[i * cols + j]);
}
}
}
void multiplication(double* m1, double* m2, double* m3, int cols, int rows) {
for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
m3[i * cols +j]=0;
for(int k = 0; k < cols; k++) {
m3[i * cols +j]+=m1[i * cols +k]*m2[k * cols +j];
}
}
}
}
void write_matrix(double* m, int cols, int rows) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
printf("%f ", m[i * cols + j]);
}
printf("\n");
}
}
int main(int argc, char* argv[])
{
char* matrix1 = argv[1];
char* matrix2 = argv[2];
if (argc < 3) {
printf("Not enough arguments.\n");
exit(-1);
}
struct mat1 m1 = dim1(matrix1);
struct mat2 m2 = dim2(matrix2);
printf(" %d %d \n", m1.cols, m1.rows);
printf(" %d %d \n", m2.cols, m2.rows);
int c1 = m1.cols;
int r1 = m1.rows;
int c2 = m2.cols;
int r2 = m2.rows;
if (r1!=c2)
{
printf("Matrixes are not suitable for multiplication. \n");
exit(-1);
}
double* mtx1 = alloc_matrix(c1, r1);
double* mtx2 = alloc_matrix(c2, r2);
FILE* f1 = fopen(matrix1, "r");
if (f1 == 0)
{
printf("Cannot open file %s.", argv[1]);
exit(-1);
}
FILE* f2 = fopen(matrix2, "r");
if (f1 == 0)
{
printf("Cannot open file %s.", argv[1]);
exit(-1);
}
read_matrix(f1, mtx1, c1, r1);
read_matrix(f2, mtx2, c2, r2);
double* mtx3 = alloc_matrix(c1, r2);
multiplication(mtx1, mtx2, mtx3, c1, r2);
write_matrix(mtx3, c1, r2);
free(mtx1);
free(mtx2);
free(mtx3);
fclose(f1);
fclose(f2);
return 0;
}
When I tried it out with 2 3x3 matrixes, The outpot:
6422164 4199040 (from 2 printf()s that I set to check the dimensions).
6422164 4199040
Matrixes are not suitable for multiplication. (it's irrelevant)
So basically it doesn't use 3x3.
I cannot figure out what the problem is.
This is prefaced by my top comments.
I had to refactor dim to handle an arbitrarily large matrix, so I had to scan the first line of the file char-by-char, counting whitespace strings (which yields the number of columns - 1). It handles/strips leading/trailing whitespace [malformed]
I had dim then rewind the file and use fscanf and realloc to create the matrix dynamically.
Here's the working code [please pardon the gratuitous style cleanup]:
#include <stdio.h>
#include <stdlib.h>
struct mat {
int cols;
int rows;
double *m;
};
// size and read in matrix
struct mat
dim(const char *file)
{
struct mat m;
int rows = 0;
int cols = 0;
int maxcnt;
int curcnt;
int ret;
int c;
int c2;
FILE *f = fopen(file, "r+");
// strip leading whitespace [if any] off first line
while (1) {
c = fgetc(f);
if (c == EOF)
break;
if (c == '\n')
break;
if (c != ' ')
break;
}
// scan first line and count columns (number of space separaters)
while (1) {
c2 = ' ';
while (1) {
c = fgetc(f);
if (c == EOF)
break;
if (c == '\n') {
if (c2 != ' ')
++cols;
break;
}
if (c == ' ') {
if (c != c2)
++cols;
break;
}
c2 = c;
}
if (c == '\n')
break;
}
// convert number of whitespace separaters into number of columns
if (cols > 0)
++cols;
rewind(f);
m.rows = 0;
m.cols = cols;
m.m = NULL;
curcnt = 0;
maxcnt = 0;
while (1) {
if (curcnt >= maxcnt) {
maxcnt += m.cols * 100;
double *tmp = realloc(m.m,sizeof(double) * maxcnt);
if (tmp == NULL) {
printf("dim: realloc failure\n");
exit(1);
}
m.m = tmp;
}
ret = 0;
for (int idx = 0; idx < cols; ++idx, ++curcnt) {
ret = fscanf(f, "%lf", &m.m[curcnt]);
if (ret != 1)
break;
}
if (ret != 1)
break;
rows += 1;
}
fclose(f);
m.rows = rows;
// trim matrix to actual size;
m.m = realloc(m.m,sizeof(double) * rows * cols);
return m;
}
double *
alloc_matrix(int cols, int rows)
{
double *m = (double *) malloc(cols * rows * sizeof(double));
if (m == 0) {
printf("Memory allocation error.\n");
exit(-1);
}
return m;
}
void
multiplication(double *m1, double *m2, double *m3, int cols, int rows)
{
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
m3[i * cols + j] = 0;
for (int k = 0; k < cols; k++) {
m3[i * cols + j] += m1[i * cols + k] * m2[k * cols + j];
}
}
}
}
void
write_matrix(double *m, int cols, int rows)
{
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
printf("%f ", m[i * cols + j]);
}
printf("\n");
}
}
int
main(int argc, char *argv[])
{
if (argc < 3) {
printf("Not enough arguments.\n");
exit(1);
}
struct mat m1 = dim(argv[1]);
struct mat m2 = dim(argv[2]);
printf(" %d %d \n", m1.cols, m1.rows);
printf(" %d %d \n", m2.cols, m2.rows);
int c1 = m1.cols;
int r1 = m1.rows;
int c2 = m2.cols;
int r2 = m2.rows;
if (r1 != c2) {
printf("Matrixes are not suitable for multiplication.\n");
exit(-1);
}
double *mtx3 = alloc_matrix(c1, r2);
multiplication(m1.m, m2.m, mtx3, c1, r2);
write_matrix(mtx3, c1, r2);
free(m1.m);
free(m2.m);
free(mtx3);
return 0;
}
Here are two test files I used. Note that although you can't see it, the first line has trailing whitespace [as a test]:
This is m1.txt:
1 2 3 4
5 6 7 8
9 10 11 12
Here is the second file:
1 2 3
4 5 6
7 8 9
10 11 12
Here is the program output:
4 3
3 4
38.000000 44.000000 202.000000 232.000000
98.000000 116.000000 438.000000 504.000000
158.000000 188.000000 674.000000 776.000000
9.000000 10.000000 87.000000 100.000000
UPDATE:
Here's an alterate dim function that replaces the [somewhat fragile] char-by-char scan of the first line with a scan for newline [to get line length], followed by malloc of a buffer, fgets, and then loop on strtok to count the non-space strings in the lines (i.e. the number of columns):
// size and read in matrix
struct mat
dim(const char *file)
{
struct mat m;
int rows = 0;
int cols = 0;
int maxcnt;
int curcnt;
int ret;
char *buf;
char *bp;
char *tok;
int c;
int c2;
FILE *f = fopen(file, "r+");
// count number of chars in first line of the file
curcnt = 0;
while (1) {
c = fgetc(f);
if (c == EOF)
break;
++curcnt;
if (c == '\n')
break;
}
++curcnt;
buf = malloc(curcnt);
rewind(f);
fgets(buf,curcnt,f);
cols = 0;
bp = buf;
while (1) {
tok = strtok(bp," \n");
if (tok == NULL)
break;
++cols;
bp = NULL;
}
free(buf);
rewind(f);
m.rows = 0;
m.cols = cols;
m.m = NULL;
curcnt = 0;
maxcnt = 0;
while (1) {
if (curcnt >= maxcnt) {
maxcnt += m.cols * 100;
double *tmp = realloc(m.m,sizeof(double) * maxcnt);
if (tmp == NULL) {
printf("dim: realloc failure\n");
exit(1);
}
m.m = tmp;
}
ret = 0;
for (int idx = 0; idx < cols; ++idx, ++curcnt) {
ret = fscanf(f, "%lf", &m.m[curcnt]);
if (ret != 1)
break;
}
if (ret != 1)
break;
rows += 1;
}
fclose(f);
m.rows = rows;
// trim matrix to actual size;
m.m = realloc(m.m,sizeof(double) * rows * cols);
return m;
}
UPDATE #2:
I didn't like either solution for getting the number of columns, so here is a cleaner one that is as fast as the first one but is simpler and less cumbersome:
// scan first line and count columns
int
colcalc(FILE *f)
{
int c;
int noncur;
int nonprev = 0;
int cols = 0;
while (1) {
c = fgetc(f);
if (c == EOF)
break;
if (c == '\n')
break;
// only count non-whitespace chars
switch (c) {
case ' ':
case '\t':
noncur = 0;
break;
default:
noncur = 1;
break;
}
// column starts on _first_ char in word
if (noncur)
cols += (noncur != nonprev);
nonprev = noncur;
}
rewind(f);
return cols;
}
UPDATE #3:
I tried out the previous 2 methods by you and it works so smoothly! Thank you once again! and your comments about making my program simpler with less variables and stuff!
You're welcome!
My coding style/methodology comes from a [very] old book: "The Elements of Programming Style" by Kernighan and Plauger.
The examples from that book are written in Fortran, but the maxims are on par with "Code Complete" by Steve McConnell.
From Chapter 7 [Efficiency and Instrumentation]:
Make it right before you make it faster.
Keep it right when you make it faster.
Make it clear before you make it faster.
Don't sacrifice clarity for small gains in "efficiency".
Don't strain to re-use code; reorganize instead.
Make sure special cases are truly special.
Keep it simple to make it faster.
Don't diddle code to make it faster -- find a better algorithm.
Instrument your programs. Measure before making "efficiency" changes.

Resources