I have written this code so far, and now i am required to use the frequency analysis to crack the code which I am not not clear of.
From what I understand, I must first count the frequency of letters in a string, then I would say compare it with the most frequent letters in German language, and later sort it with bubble sort. Is this correct?
I would really appreciate it if anyone could give me Ideas or hints on where to start. Thank you in advance.
EDITED: Hi Guys, i just edited my code and the frequency analysis seems to be working fine right now. It would help me if you guys can give comments or critics on my code. Thanks!
BTW its German language, i changed it.
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <ctype.h>
#define MAX 100
struct Data
{
char letter;
int num;
};
typedef struct Data DATA;
void encode(char message[], int shift)
{
int i;
FILE *pout;
pout = fopen("Output_encode.txt", "w");
if (pout == NULL)
{
printf("File could not be opened for writing!\n");
exit(1);
}
for(i=0;i<strlen(message);i++)
{
if (!isalpha(message[i]))
continue;
// checking for upper case
if(isupper(message[i]))
message[i]=((message[i]-'A') + shift) % 26 + 'A';
else
//checking for lower case
if(islower(message[i]))
message[i]=((message[i]-'a') + shift) % 26 + 'a';
}
printf("\n\tEncoded text: %s\n", message);
fprintf(pout, "%s\n", message);
if (fclose(pout) != 0)
printf("Error in closing file!\n");
}
void decode(char message[], int shift)
{
int i;
FILE *pout;
pout = fopen("Output_decode.txt", "w");
if (pout == NULL)
{
printf("File could not be opened for writing!\n");
exit(1);
}
for(i=0;i<strlen(message);i++)
{
if (!isalpha(message[i]))
continue;
// checking for upper case
if(isupper(message[i]))
message[i]=((message[i]-'A') + (26-shift)) % 26 + 'A';
else
//checking for lower case
if(islower(message[i]))
message[i]=((message[i]-'a') + (26-shift)) % 26 + 'a';
}
printf("\n\tDecoded text: %s\n", message);
fprintf(pout, "%s\n", message);
if (fclose(pout) != 0)
printf("Error in closing file!\n");
}
void textfile_decode()
{
FILE *pin, *pout;
char filename_in[MAX], filename_out[MAX];
char text[MAX];
char text3[MAX]={0};
char table[26] = {'e','n','i','r','s','t','a','d','h','u','l','c','g','o','m','b','f','w','k','z','p','v','j','y','x','q'}; //Frequency letters in German dictionary
DATA temptext, text2[26];
int temp, position;
int i, m, max, trial, l=0, n=0, k=0;
printf("Enter name of input file: ");
scanf("%s", filename_in);
pin = fopen(filename_in, "r");
if (pin == NULL)
{
printf("File could not be opened for reading!");
}
printf("Enter name of output file: ");
scanf("%s", filename_out);
pout = fopen(filename_out, "w");
if (pout == NULL)
{
printf("File could not be opened for writing!");
}
printf("\nOriginal Code:\n");
while(!feof(pin))
{
fgets(text, MAX, pin); //Read from textfile
fputs(text, stdout); //Show original code on console
}
printf("\n");
if (pin == NULL)
{
printf("File could not be opened for reading!");
}
fclose(pin);
pin = fopen(filename_in, "r");
for (i = 0; i <= 25; i++)
{
text2[i].letter = 'a' + i; //Array elements A-Z
text2[i].num = 0; //Number of letters (Frequency)
}
while(!feof(pin))
{
i = 0;
fgets(text, MAX, pin); //Read from textfile per line
while(text[i] != '\0')
{
if(1 == isupper(text[i])) // Replace capital letters with small
{
text[i] += 32;
}
switch(text[i]) //Counting letters (letter frequency)
{
case 'a':
text2[0].num += 1;
break;
case 'b':
text2[1].num += 1;
break;
case 'c':
text2[2].num += 1;
break;
case 'd':
text2[3].num += 1;
break;
case 'e':
text2[4].num += 1;
break;
case 'f':
text2[5].num += 1;
break;
case 'g':
text2[6].num += 1;
break;
case 'h':
text2[7].num += 1;
break;
case 'i':
text2[8].num += 1;
break;
case 'j':
text2[9].num += 1;
break;
case 'k':
text2[10].num += 1;
break;
case 'l':
text2[11].num += 1;
break;
case 'm':
text2[12].num += 1;
break;
case 'n':
text2[13] .num+= 1;
break;
case 'o':
text2[14].num += 1;
break;
case 'p':
text2[15].num += 1;
break;
case 'q':
text2[16].num += 1;
break;
case 'r':
text2[17].num += 1;
break;
case 's':
text2[18].num += 1;
break;
case 't':
text2[19].num += 1;
break;
case 'u':
text2[20].num += 1;
break;
case 'v':
text2[21].num += 1;
break;
case 'w':
text2[22].num += 1;
break;
case 'x':
text2[23].num += 1;
break;
case 'y':
text2[24].num += 1;
break;
case 'z':
text2[25].num += 1;
break;
default: break;
}
i++;
}
}
for(i = 0; i <= 26; i++) // Sorting array text2 according to letter frequency
{
temp = text2[i].num;
for(m = i+1; m <= 27; m++)
{
if(text2[m].num > temp)
{
max = m;
temp = text2[m].num;
}
}
temptext = text2[max];
text2[max] = text2[i];
text2[i] = temptext;
}
fclose(pin);
fclose(pout);
pin = fopen(filename_in, "r");
pout = fopen(filename_out, "w");
do
{
k += 1;
} while (text2[k].num == text2[k+1].num); //Check--> How many letters have the same frequency
trial = 2;
while(!feof(pin))
{
fgets(text, MAX, pin);
do
{
position = table[l] - text2[n].letter; // determine letter position
i = 0;
do
{
if(0 !=isalpha(text[i]))
{
if(0 != isupper(text[i])) // Checking for uppercase
{
text3[i] = text[i];
text3[i] = text3[i] + position;
if(text3[i] > 90) // If exceeds Alphabets, start again from 'A'
{
text3[i] = text3[i] - 26;
}
else if (text3[i] < 65)
{
text3[i] += 26;
}
}
else if (0 != islower(text[i])) // checking for lowercase
{
text3[i] = text[i];
text3[i] = text3[i] + position;
if(text3[i] > 122) // If exceeds Alphabets, start again from 'a'
{
text3[i] = text3[i] - 26;
}
else if(text3[i] < 97)
{
text3[i] += 26;
}
}
}
else
{
text3[i] = text[i]; // All other non letters are simply replaced
}
i++;
}while(text[i] != '\0' );
if (trial== 2)
{
printf("\n");
fputs(text3, stdout);
printf("\nCode decrypted? (0)NO (1)YES : ");
scanf("%d", &trial);
printf("\n");
}
if (trial == 0 && n != k) // Code not decrypted, letters have different frequency
{
n++;
trial = 2;
}
if (trial == 0 && n == k) // Code not decrypted, letters have same frequency
{
l++;
n = 0;
trial = 2;
}
if (trial == 3) // First line of code is decrypted, following lines will decrypted using same shift position
{
trial = 1;
}
}while(trial != 1);
fputs(text3, stdout); //Show on console window
fputs(text3, pout);
memset(text3,'\0',100); // Reset text3 array
memset(text,'\0',100); // Reset text array
trial = 3; // First line of code decrypted, shift position is saved
}
fclose(pin);
fclose(pout);
}
int main()
{
int shift, choice1, choice2;
char message[MAX];
do{
printf("Selection: \n");
printf("(1) Encode/Decode\n");
printf("(2) Decode Textfile\n");
printf("(3) End Programme\n");
printf("User input: ");
scanf("%d", &choice1);
fflush(stdin);
switch(choice1){
case 1:
printf("\nEnter message to be encrypted: ");
gets(message);
printf("Enter shift amount (1-25): ");
scanf("%d", &shift);
printf("\nSelection: \n");
printf("(1) Encode\n");
printf("(2) Decode\n");
printf("User input: ");
scanf("%d", &choice2);
switch(choice2)
{
case 1:
encode(message, shift);
break;
case 2:
decode(message, shift);
break;
}
break;
case 2:
textfile_decode();
break;
}
printf("\n\n");
}while(choice1!=3);
printf("\n");
return 0;
}
A Caesar ciphre changes characters by shifting them n places.
There are two very simple approaches to solving a shift ciphre:
Print all 25 possible solutions. Manually select the one that contains readable text.
Get the frequency of the characters (not the words). Then perform the shift that best aligns with a frequency table of the language the message was written in (English in your case?).
To break the code you can use 3 different approaches:
The first one is what you cited: count the frequency of words in a text ( I would rather use a Map for that, using the string as key and rising the number of hits as value.), and guessing the letters by comparing it to the frequency of words used in normal texts.
The second solution would be to do same with letters and guessing the meaning by comparing your frequency with the frequency of letters in a normal text.
The third solution would be to take single words of the text and trying all possible shiftings of the letters until you get words that mean something.
Here you can find some good sources!
Related
I have a task to make smth like t9 like it was in old phones (number can also mean some combination of letters). For example, if user run it this way ./t9search 23 < list.txt, program should return numbers which has this combination of digits or letters that corresponds to them (in this case a,b,c and d,e,f). It's also forbidden to work with dynamic memory(malloc, free) and functions with algorithms (qsort, lsearch etc). Format of information in file is "name\n number\n name\n number\n...".
The loop doesn't work correctly but I can't find a mistake. The program should return {Name}, {number}but it return only numbers.
The code is:
`
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define FULFILLED 1
#define NOT_FULFILLED 0
int main(int argc, char **argv)
{
char line[99];
int line_no = -1;
int size = strlen(argv[1]);
char letters[size][5];
int total_combinations = 1;
char combinations[total_combinations][size + 1];
int current_combination[size];
int check_name = NOT_FULFILLED;
char name[99];
for(int i = 0; argv[1][i]; i++)
{
switch(argv[1][i]) //cases according to input
{
case '0':
strcpy(letters[i], "+");
break;
case '2':
strcpy(letters[i], "abc");
break;
case '3':
strcpy(letters[i], "def");
break;
case '4':
strcpy(letters[i], "ghi");
break;
case '5':
strcpy(letters[i], "jkl");
break;
case '6':
strcpy(letters[i], "mno");
break;
case '7':
strcpy(letters[i], "pqrs");
break;
case '8':
strcpy(letters[i], "tuv");
break;
case '9':
strcpy(letters[i], "wxyz");
break;
}
total_combinations *= strlen(letters[i]); //number of combinations of letters from array elements
}
for (int i = 0; i < size; i++)
{
current_combination[i] = 0;
}
int k = 0;
while (k < total_combinations)
{
for (int set_idx = 0; set_idx < size; set_idx++)
{
int letter_idx = current_combination[set_idx];
combinations[k][set_idx] = letters[set_idx][letter_idx];
}
combinations[k][size] = '\0';
for(int i = size - 1; i >= 0; i--)
{
current_combination[i]++;
if (current_combination[i] == strlen(letters[i]))
{
current_combination[i] = 0;
}
else
{
break;
}
}
k++;
}
printf("%c\n", sizeof(combinations)/sizeof(combinations[0]));
while(fgets(line, sizeof(line), stdin))
{
line_no++;
if (line_no % 2 == 0) //even lines (names)
{
name[99] = line; //variable to use name with number
for (int i = 0; i < total_combinations; i++) //for each combination from array with combinations
{
if (strstr(line, combinations[i])) //if combination is a substring of a string
{
check_name = FULFILLED;
}
}
}
else if (line_no % 2 == 1) //odd lines (numbers)
{
if (check_name == FULFILLED || strstr(line, argv[1])) // if there's name that corresponds with input OR input is a substring of a string
{
printf("%s, %s", name, line);
check_name = NOT_FULFILLED;
}
}
}
}
`
I've tried to change the way of checking names:
if (line_no % 2 == 0)
{
for (int j = 0; j <= strlen(letters); j++)
{
char let = getchar();
for (int i = 0; i < strlen(line); i++)
{
if (letters[j] == line[i])
{
check_name = FULFILLED;
continue;
}
else if (letters[j] != line [i])
{
break;
}
}
}
}
Sure I didn't reach success. So I'd be extremely grateful for any help.
Arrays do not resize reflectively when the variables used to create them change. They are sized permanently at the time of their initialization. The following
int total_combinations = 1;
char combinations[total_combinations][size + 1];
/* ... */
total_combinations *= strlen(letters[i]);
does not cause combinations to grow as total_combinations does. Move the definition of combinations to after total_combinations has been fully computed.
The following attempts to assign a char * to a char, and also indexes name out of bounds.
name[99] = line;
As done previously, use strcpy to copy strings.
Note that, if found and if there is room in the buffer, fgets stores the newline character in the buffer, so
printf("%s, %s", name, line);
will very likely print staggered output, like
Alice
, 5551234567
A cursory refactoring:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *remove_newline(char *string)
{
if (string)
string[strcspn(string, "\n")] = '\0';
return string;
}
int main(int argc, char **argv)
{
if (argc < 2) {
fprintf(stderr, "usage: %s t9_sequence\n", argv[0]);
return EXIT_FAILURE;
}
int size = strlen(argv[1]);
char letters[size][5];
int total_combinations = 1;
int current_combination[size];
for (int i = 0; argv[1][i]; i++) {
switch (argv[1][i]) {
default:
fprintf(stderr, "Invalid input: \"%c\"\n", argv[1][i]);
return EXIT_FAILURE;
case '0':
strcpy(letters[i], "+");
break;
case '2':
strcpy(letters[i], "abc");
break;
case '3':
strcpy(letters[i], "def");
break;
case '4':
strcpy(letters[i], "ghi");
break;
case '5':
strcpy(letters[i], "jkl");
break;
case '6':
strcpy(letters[i], "mno");
break;
case '7':
strcpy(letters[i], "pqrs");
break;
case '8':
strcpy(letters[i], "tuv");
break;
case '9':
strcpy(letters[i], "wxyz");
break;
}
total_combinations *= strlen(letters[i]);
}
memset(current_combination, 0, sizeof current_combination);
char combinations[total_combinations][size + 1];
for (int k = 0; k < total_combinations; k++) {
for (int set_idx = 0; set_idx < size; set_idx++) {
int letter_idx = current_combination[set_idx];
combinations[k][set_idx] = letters[set_idx][letter_idx];
}
combinations[k][size] = '\0';
for (int i = size - 1; i >= 0; i--) {
current_combination[i]++;
if (current_combination[i] != strlen(letters[i]))
break;
current_combination[i] = 0;
}
}
char name[128];
char number[128];
while (1) {
if (!fgets(name, sizeof name, stdin))
break;
if (!fgets(number, sizeof number, stdin))
break;
int found = 0;
for (int i = 0; i < total_combinations; i++) {
if (strstr(name, combinations[i])) {
found = 1;
break;
}
}
if (found || strstr(number, argv[1]))
printf("%s, %s\n", remove_newline(name), remove_newline(number));
}
}
Given an integer n, the program has to delete each word, that contains the n number of vowels.
The string is read from a test.txt file, which contains the following:
Astazi nu este maine.
Currently my program contains a count1 function, that counts the number of characters and vowels for each word in the string.
How can I use the data from count1 function as a refference when typing in the n vowels to delete the needed words then print the updated string?
I have an idea, which I'm unsure how to implement. In count1 we already count the number of vowels per each word, so, given n by the user we check if this number is equal to v in the count1 function and so we do int num_of_words++, then we do a loop, which prints out the needed words, until num_of_words=0
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
void count1 (char* str)
{
for (int i = 0;;)
for (int v = 0, w = i;;)
{
int len;
char c = str[i++];
switch (c)
{
case 'A':
case 'E':
case 'I':
case 'O':
case 'U':
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
v++;
default:
continue;
case ' ':
case '\t':
case '\n':
case '\0':
len = i - 1 - w;
printf("'%.*s': %d characters, %d vowels\n", len, str+w, len, v );
if (c)
break;
else
return;
}
break;
}
}
void count2 (char* str, int n)
{
char line2[128];
int ls=strlen(str);
for (int i = 0;;)
for (int v = 0, w = i;;)
{
int len;
char c = str[i++];
switch (c)
{
case 'A':
case 'E':
case 'I':
case 'O':
case 'U':
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
v++;
default:
continue;
case ' ':
case '\t':
case '\n':
case '\0':
for(int k = 0; str[k] != '\0'; k++)
{
if (k == 0 || isspace(str[k]))
{
if(v==n)
{
strcat(line2, str+1);
}
}
}
printf("%s ", line2);
if (c)
break;
else
return;
}
break;
}
}
int main()
{
FILE *fp;
char line[128];
int c=0, count[26]= {0}, x;
int n;
fp = fopen("test.txt", "r");
fscanf(fp, "%[^\n]", line);
fclose(fp);
printf("%s\n\n", line);
while (line[c] != '\0')
{
if (line[c] >= 'a' && line[c] <= 'z')
{
x = line[c] - 'a';
count[x]++;
}
c++;
}
for (c = 0; c < 26; c++)
{
printf("%c occurs %d times.\n", c + 'a', count[c]);
}
printf("\n");
count1(line);
printf("\nInsert n: ");
scanf("%d", &n);
count2(line, n);
return 0;
}
If you have a string str that consists of separate words, separated one from another by ' ' or '\n' or '\t', and you want to have a string that contains all the words in str that satisfy some condition, it will be a bit difficult to program it such that it will be "in-place", i.e. to change str to the desired string, without using a "helper array" of some sort.
Instead, I would recommend to create a new char array with the same size (say str2), and every time you find a word that satisfies the condition (the condition can be for example: doesn't have 1 vowel), you copy the word that you found from str to str2.
Something like this:
char str[128];
// read from file to str using fscanf
char str2[128];
for (int c = 0; str[c] != '\0'; ++c)
{
if (c == 0 || isspace(str[c]))
{
if (! is_1_vowel[str+1]) // if it doesn't have exacly one vowel
{
// copy the word from str to str2
strcat_word(str2, str+1); // a user-defined adapted version of strcat that will copy from src to dest only till src reaches a space character or '\0'
}
}
}
I'm assuming here that is_1_vowel will be a function that goes over a single word (and not the whole line or file), and returns 1 if it satisfies the condition (has 1 vowel), and returns 0 otherwise.
Here's my final solution
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
void count1 (char* str)// count numbers of vowels for each word
{
for (int i = 0;;)
for (int v = 0, w = i;;)
{
int len;
char c = str[i++];
switch (c)
{
case 'A':
case 'E':
case 'I':
case 'O':
case 'U':
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
v++;
default:
continue;
case ' ':
case '\t':
case '\n':
case '\0':
len = i - 1 - w;
printf("'%.*s': %d characters, %d vowels\n", len, str+w, len, v );
if (c)
break;
else
return;
}
break;
}
}
void print_x(char* str, int n)
{
char* tmp;
unsigned int cnt = 0, stat = 0;
const char aeiou[] = "AEIOUaeiou";
while(*str)
{
switch(stat)
{
case 0://the word did not start
if (!isalpha(*str))
{
putchar(*str);
break;
}
stat = 1;
tmp = str;
cnt = 0;
case 1://the word started
if (strchr(aeiou, *str))
{
cnt++;
break;
}
if (! isalpha(*str))
{
if (cnt != n)
while(tmp <= str) putchar(*(tmp++));
else putchar(*str);
stat = 0;
}
} // end switch
++str;
}
if (stat)
{
--str;
if (cnt != n) while(tmp <= str) putchar(*(tmp++));
}
}
int main()
{
FILE *fp;
char line[128], line2[128];
int c=0, count[26]= {0}, x;
int n,a;
int i,j;
fp = fopen("test.txt", "r");
fscanf(fp, "%[^\n]", line);
fclose(fp);
printf("%s\n\n", line);
while (line[c] != '\0')
{
if (line[c] >= 'a' && line[c] <= 'z')
{
x = line[c] - 'a';
count[x]++;
}
c++;
}
for (c = 0; c < 26; c++)
{
printf("%c occurs %d times.\n", c + 'a', count[c]);
}
for (i = 0; i < 26; ++i)
{
for (j = i + 1; j < 26; ++j)
{
if (count[i] < count[j])
{
a = count[i];
count[i] = count[j];
count[j] = a;
}
}
}
printf("\n\n");
for (c = 0; c < 26; c++)
{
printf("%c occurs %d times.\n", c + 'a', count[c]);
}
printf("\n");
count1(line);
printf("\nInsert n: ");
scanf("%d", &n);
if (!(fp = fopen("./test.txt", "r")))
{
printf("unable open file\n");
return 1;
}
while (fgets(line, 128, fp))
print_x(line, n);
fclose(fp);
return 0;
}
I am writing this code that takes a calculation from a file on the command line, then calculates it. I have gotten to a point where I am able to get each part of the file into a string array, however when I try to run that array into a method to calculate it, I get an abort trap: 6 error during run time. I am writing in c using emacs and the cc in the terminal to compile.
I am running this in main when it gives the error, with these variables initialized:
char items[10][10];
int sig;
int numOfItems = n-1;
double result[3];
sig=calculate(items, numOfItems, result);
The method is the following, I know it does not fully work yet, but it seems to not even enter the method because it does not print out the test print statements I have put:
int calculate(char items[10][10], int numOfItems, double *res){
printf("test2");
int flag, i, c, j, numdigits, decindicate, operatorindicate,n,m;
double ans;
double numbers[30];
char operators[30];
for(n=0; n<30; n++){
numbers[n]=0;
}
flag=1;
i=0;
numdigits=0;
decindicate=0;
operatorindicate=0;
n=0;
m=0;
j=0;
while(n<numOfItems){
c=items[n][0];
if(('0'<=c) && (c<='9')){
m=0;
while(c!='\0'){
c=items[n][m];
if(('0'<=c) && (c<='9')){
numbers[i] = numbers[i]*10+(c-'0');
}else if(c=='.'){
decindicate=1;
m++;
break;
}else{
flag=0;
break;
}while(decindicate>0){
c=items[n][m];
if(('0'<=c) && (c<='9')){
numbers[i]=numbers[i]+((c-'0')/(10^decindicate));
decindicate++;
}else{
flag=0;
break;
}m++;
}
i++;
}
}else if(c=='+' || c=='-' || c=='*' || c=='/'){
operators[j]=c;
j++;
}else{
flag=0;
break;
}n++;
}
for(i=0; i<numdigits; i++){
printf("%lf \n",numbers[i]);
}for(i=0; i<m; i++){
printf("char %c \n", operators[i]);
}
ans=numbers[0];
for(i=0; i<n-1; i++){
if(operators[i]=='+'){
ans=ans+numbers[i+1];
}else if(operators[i]=='-'){
ans=ans-numbers[i+1];
}else if(operators[i]=='*'){
ans=ans*numbers[i+1];
}else if(operators[i]=='/'){
ans=ans/numbers[i+1];
}
}
*res=ans;
return flag;
}
Here is the entire code if it's something out of these bounds that I don't even realize:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
int calculate(char items[10][10], int numOfItems, double *res){
int flag, i, c, j, numdigits, decindicate, operatorindicate,n,m;
double ans;
double numbers[30];
char operators[30];
for(n=0; n<30; n++){
numbers[n]=0;
}
flag=1;
i=0;
numdigits=0;
decindicate=0;
operatorindicate=0;
n=0;
m=0;
j=0;
while(n<numOfItems){
c=items[n][0];
if(('0'<=c) && (c<='9')){
m=0;
while(c!='\0'){
c=items[n][m];
if(('0'<=c) && (c<='9')){
numbers[i] = numbers[i]*10+(c-'0');
}else if(c=='.'){
decindicate=1;
m++;
break;
}else{
flag=0;
break;
}while(decindicate>0){
c=items[n][m];
if(('0'<=c) && (c<='9')){
numbers[i]=numbers[i]+((c-'0')/(10^decindicate));
decindicate++;
}else{
flag=0;
break;
}m++;
}
i++;
}
}else if(c=='+' || c=='-' || c=='*' || c=='/'){
operators[j]=c;
j++;
}else{
flag=0;
break;
}n++;
}
for(i=0; i<numdigits; i++){
printf("%lf \n",numbers[i]);
}for(i=0; i<m; i++){
printf("char %c \n", operators[i]);
}
ans=numbers[0];
for(i=0; i<n-1; i++){
if(operators[i]=='+'){
ans=ans+numbers[i+1];
}else if(operators[i]=='-'){
ans=ans-numbers[i+1];
}else if(operators[i]=='*'){
ans=ans*numbers[i+1];
}else if(operators[i]=='/'){
ans=ans/numbers[i+1];
}
}
*res=ans;
return flag;
}
int main(int argc, char **argv){
int n, m, i;
char digits[50]; //used to store digits before adding necessary spaces
char items[10][10]; //will store string array of items in equation
FILE *fp, *fp2;
int sig; //will indicate if there is an invalid character
double result[3] = {0}; //will return result of equation
fp = fopen(argv[1], "r");
if(fp==NULL){
printf("Please provide file");
}
fp2 = fopen("temp", "w+"); //will read to file temp
n=0;
while(0==0){
digits[n]=fgetc(fp);
if(digits[n]==EOF){
digits[n]='\0';
break;
}
n++;
}
n=0;
char temp1;
char temp2;
while(digits[n]!='\0'){
if((('0'<=digits[n]) && (digits[n]<='9') && (digits[n+1]=='+' || digits[n+1]=='-' || digits[n+1]=='*' || digits[n+1]=='/')) || ((digits[n]=='+' || digits[n]=='-' || digits[n]=='*' || digits[n]=='/') && (('0'<=digits[n+1]) && (digits[n+1]<='9')))){
temp1=digits[n+1];
digits[n+1]=' ';
m=n+2;
while(digits[m-1]!='\0'){
temp2=temp1;
temp1=digits[m];
digits[m]=temp2;
m++;
}
}
fputc(digits[n], fp2);
n++;
}
//test if digit array fills correctly
n=0;
while(digits[n]!='\0'){
printf("testings digits array: %c \n", digits[n]);
n++;
}
//scans the temp file to form string array
rewind(fp2);
i=1;
n=0;
while(i==1){
i=fscanf(fp2, "%s", items[n]);
n++;
}
int numOfItems = n-1;
//test if char array items fills correctly
n=0;
while(n<numOfItems){
printf("testing items array: %s \n", items[n]);
n++;
}
sig=calculate(items, numOfItems, result);
if (sig==0){
printf("This is not a valid operation. \n");
}else {
printf("The calculation equals %lf \n", result[0]);
}
remove("temp");
}
the file I am using to test is sc1 which contains the following:
34 + 96 - 10 / 2
This is what the whole program prints out when using this sc1 file:
testings digits array: 3
testings digits array: 4
testings digits array:
testings digits array: +
testings digits array:
testings digits array: 9
testings digits array: 6
testings digits array:
testings digits array: -
testings digits array:
testings digits array: 1
testings digits array: 0
testings digits array:
testings digits array: /
testings digits array:
testings digits array: 2
testing items array: 34
testing items array: +
testing items array: 96
testing items array: -
testing items array: 10
testing items array: /
testing items array: 2
Abort trap: 6
I feel so lost, if someone could help that would be great.
in calculate the while(c!='\0') was an infinite loop. c=items[n][m]; never got a new value for c as m wasn't incremented unless a dot was detected. i was incremented so each iteration accessed numbers[i] and when i exceeded the boundary of numbers[30] it failed.
numbers[i]=numbers[i]+((c-'0')/(10^decindicate)); is another problem as ^ is bit XOR. Not what you want here to raise the power of 10.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
int calculate(char items[10][10], int numOfItems, double *res){
int flag = 1, i = 0, c, ops = 0, decindicate = 0, nums = 0,item = 0,each = 0;
double ans;
double numbers[30] = { 0.0};
char operators[30];
printf ( "calculating\n");
while ( item < numOfItems) {
c = items[item][0];
if ( ( '0' <= c && c <= '9') || c == '.') {
each = 0;
decindicate = 0;
while ( '\0' != ( c = items[item][each])) {
if ( ( '0' <= c) && ( c <= '9')) {
numbers[nums] = numbers[nums] * 10 + ( c - '0');
if ( decindicate) {
decindicate++;
}
}
else if ( c == '.') {//found a dot
decindicate = 1;//set to 1
each++;
continue;
} else {
flag = 0;
break;
}
each++;//advance each character
}
while ( decindicate > 1) {
decindicate--;
numbers[nums] /= 10;//divide by power of 10 digits after dot
}
nums++;//advance nums
if ( nums >= 30) {
printf ( "too many numbers\n");
return 0;
}
} else if ( c == '+' || c == '-' || c == '*' || c == '/') {
operators[ops] = c;
ops++;//sdvance ops
if ( ops >= 30) {
printf ( "too many operators\n");
return 0;
}
} else {
flag = 0;
break;
}
item++;//advance item
}
for ( i = 0; i < nums; i++) {
printf ( "numbers %f \n", numbers[i]);
}
for ( i = 0; i < ops; i++) {
printf ( "operators %c \n", operators[i]);
}
ans = numbers[0];
for ( i = 0; i < item - 1; i++) {
switch ( operators[i]) {
case '+':
ans = ans + numbers[i + 1];
break;
case '-':
ans = ans - numbers[i + 1];
break;
case '*':
ans = ans * numbers[i + 1];
break;
case '/':
ans = ans / numbers[i + 1];
break;
}
}
*res = ans;
return flag;
}
int main ( int argc, char **argv) {
int n = 0, i, digit = 0;
char digits[50] = ""; //used to store digits before adding necessary spaces
char items[10][10] = { { ""}}; //will store string array of items in equation
FILE *fp = NULL, *fp2 = NULL;
int sig = 0; //will indicate if there is an invalid character
int space = 1;//skip leading whitespace
int operator = 1;//must have a number first
int number = 0;
int dot = 0;
double result = 0.0f; //will return result of equation
if ( NULL == ( fp = fopen ( argv[1], "r"))) {
printf ( "Please provide file\n");
return 0;
}
if ( NULL == ( fp2 = fopen ( "temp", "w+"))) { //will read to file temp
printf ( "could not open temp file\n");
fclose ( fp);
return 0;
}
n = 0;
while ( EOF != ( digit = fgetc ( fp))) {
digits[n] = digit;
n++;
if ( n >= 49) {
break;
}
}
digits[n] = '\0';
fclose ( fp);
n = 0;
while ( digits[n] != '\0') {
switch ( digits[n]) {
case ' ':
case '\t':
case '\n':
if ( space) {
break;
}
space = 1;
//do not reset so as to detect consecutive numbers or operators
//number = 0;
//operator = 0;
dot = 0;
fputc ( digits[n], fp2);
break;
case '.':
if ( dot) {
break;
}
if ( space && number) {
printf ( "bad format. expected operation\n");
return 0;
}
if ( !number) {
fputc ( ' ', fp2);
}
space = 0;
number = 1;
operator = 0;
dot = 1;
fputc ( digits[n], fp2);
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if ( space && number) {
printf ( "bad format. expected operation\n");
return 0;
}
if ( !number) {
fputc ( ' ', fp2);
}
space = 0;
number = 1;
operator = 0;
dot = 0;
fputc ( digits[n], fp2);
break;
case '+':
case '-':
case '*':
case '/':
if ( space && operator) {
printf ( "bad format. expected number\n");
return 0;
}
if ( !operator) {
fputc ( ' ', fp2);
}
number = 0;
operator = 1;
dot = 0;
fputc ( digits[n], fp2);
space = 1;
fputc ( ' ', fp2);
break;
}
n++;
}
//scans the temp file to form string array
rewind(fp2);
i = 1;
n = 0;
while ( i == 1) {
i = fscanf ( fp2, "%s", items[n]);
n++;
if ( n >= 10) {
break;
}
}
fclose ( fp2);
int numOfItems = n-1;
//test if char array items fills correctly
n = 0;
while ( n < numOfItems) {
printf ( "testing items array: %s \n", items[n]);
n++;
}
sig = calculate ( items, numOfItems, &result);
if ( sig == 0) {
printf ( "This is not a valid operation. \n");
} else {
printf ( "The calculation equals %lf \n", result);
}
remove ( "temp");
return 0;
}
I'm relatively new to C programming and I am trying to code a program that reads in a user's marks and assign a grade to the mark inputted.
I have used the getline() function to acquire user input. Below is my code.
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <ctype.h>
int getMark();
void display(char grade);
char convert(int mark);
int getMark() {
do {
int marks;
char * buffer;
char characters;
size_t bufsize = 16;
buffer = (char *)malloc(bufsize * sizeof(char));
if( buffer == NULL) {
perror("Unable to allocate buffer");
exit(1);
}
printf("Enter the score (0 - 100)\nOr just press the enter key to quit ==> ");
characters = getline(&buffer, & bufsize, stdin);
int i;
long check;
for (i = 0; i < sizeof(buffer); i++) {
if (buffer[i] == '\n' && i != 0) {
buffer[i] = '\0';
}
if (isdigit(buffer[i]) || buffer[i] == '\0') {
check++;
}
}
if (buffer[0] == '\n') {
return -1;
} else if (check == strlen(buffer) - 1) {
marks = atoi(buffer);
} else {
printf("Please enter an integer.\n");
continue;
}
if (marks >= 0 && marks <= 100) {
return marks;
} else {
printf("Sorry, your marks can only be between 0 to 100.\n");
continue;
}
} while (1);
}
void display(char grade) {
printf("The grade for the input score is %c \n", grade);
}
char convert(int mark) {
mark /= 10;
char grade;
switch(mark) {
case 0:
case 1:
case 2:
case 3:
grade = 'F';
break;
case 4:
grade = 'E';
break;
case 5:
grade = 'D';
break;
case 6:
grade = 'C';
break;
case 7:
grade = 'B';
break;
case 8:
case 9:
case 10:
grade = 'A';
}
return grade;
}
int main() {
int marks;
for (;;) {
marks = getMark();
if (marks == -1) {
break;
}
display(convert(marks));
}
return 0;
}
When I press Enter, the program exits, as expected.
However, when an integer is entered, for example 12, the output will always be Please enter an integer.
Can anyone help me on this? Thanks!
char * buffer;
...
for (i = 0; i < sizeof(buffer); i++) {
if (buffer[i] == '\n' && i != 0) {
sizeof(buffer) returns the size of a pointer to char (4 or 8 bytes depending on the architecture), not the length of the string, in consequence, you are reading outside of the bounds of the array when 12 is entered.
Change to strlen() or better yet, use the result of getline:
On success, getline() and getdelim() return the number of characters
read, including the delimiter character, but not including the
terminating null byte ('\0').
I want to that this function after than player 1 puts position program chack where on the left is player's 1 pawn and all of opponent's paws between player's 1 two pawns turning on 'X', like in reversi games.
This is whole unfinished code:
#include<stdio.h>
#define SIZE 7
char board[SIZE][SIZE];
char letter;
int number;
void make_board(char tab[SIZE][SIZE]){
int w,k;
for(w=0; w < SIZE; w++){
for(k=0; k < SIZE; k++){
tab[w][k] = '.';
}
}
tab[0][0] = 'X';
tab[1][0] = '1';
tab[2][0] = '2';
tab[3][0] = '3';
tab[4][0] = '4';
tab[5][0] = '5';
tab[6][0] = '6';
tab[0][1] = 'A';
tab[0][2] = 'B';
tab[0][3] = 'C';
tab[0][4] = 'D';
tab[0][5] = 'E';
tab[0][6] = 'F';
tab[4][4] = 'X';
tab[4][3] = 'O';
tab[3][4] = 'O';
tab[3][3] = 'X';
}
char draw_board(char tab[SIZE][SIZE]){
int w, k;
for(w=0; w < SIZE; w++){
for(k=0; k < SIZE; k++){
printf("%2c", tab[w][k]);
}
printf("\n");
}
}
int translate(char letter){
int letter_to_number;
switch(letter){
case 'A':
case 'a':
letter_to_number = 1;
break;
case 'B':
case 'b':
letter_to_number = 2;
break;
case 'C':
case 'c':
letter_to_number = 3;
break;
case 'D':
case 'd':
letter_to_number = 4;
break;
case 'E':
case 'e':
letter_to_number = 5;
break;
}
return letter_to_number;
}
int finished(char tab[SIZE][SIZE]){ // looking '.' in array
int i,j;
for(i=1;i<=SIZE;i++){
for(j=1;j<=SIZE;j++){
if(tab[i][j]=='.'){
return 1;
}else{
return 0; // if don't find any '.' game is finish
}
}
}
}
void hit(char tab[SIZE][SIZE], int player ){
int i,j;
int *poz1, *poz2;
printf("Call out a letter and a number of a row and column on the grid:\n");
scanf(" %c %d", &letter, &number);
i=translate(letter);
poz1=&tab[number][i];
if(tab[number][i]=='.'){
if(player==1){
*poz1='X';
for(poz1-1;*poz1=='X';poz1--){
poz2=&poz1;}
poz1=&tab[number][i];
for(poz2;poz2<=poz1;poz2++){
*poz2='X';}
}else{
*poz1='O';
for(poz1-1;*poz1=='O';poz1--){
poz2=&poz1;}
poz1=&tab[number][i];
for(poz2;poz2<=poz1;poz2++){
poz2='O';}
}
}else{
printf("On this place already is pawn\n");
}
draw_board(board);
getchar();
}
int main(){
int i,j,k, pg1=0, pg2=0, player=1;
make_board(board);
draw_board(board);
do{
if(player==1){
printf("Player 1\n");
hit(board, gracz);
k=finished(board);
gracz=2;
}else{
printf("Player 2\n");
hit(board, gracz);
k=finished(board);
player=1;
}
}while(k==1);
for(i=1;i<=SIZE;i++){
for(j=1;j<=SIZE;j++){
if(board[i][j]=='X'){
pg1++;
}else{
pg2++;
}
}
}
if(pg1>pg2){
printf("Player 1 wins");
}else{
printf("Player 2 wins");
}
return 0;
}
Bit buggy code:
poz1=&tab[number][i];
if(tab[number][i]=='.'){
if(player==1){
*poz1='X';
for(poz1-1;*poz1=='X';poz1--){
poz2=&poz1;}
poz1=&tab[number][i];
for(poz2;poz2<=poz1;poz2++){
*poz2='X';}
How can you asgn &pos1 to pos2. For this you need pointer to a pointer, i.e, pos 2 should be declared as **pos2.
Also, what do you want to achieve by looping over poz1 (set 'X' earlier)?
Anyhow, some cleanup to your code:
if(tab[number][i]=='.'){
if(player==1){ //considering player 1 is 'X'
// Loop to the left till you find opponent's piece or come to edge.
for(j=i-1;tab[number][j]=='O' && j!=0 ;j--)
;
// Validation check
if(i-j <=1 || tab[number][j] != 'X');
//Invalid move
return 1;
else
// convert all the opponents pieces between two of yours piece
for(k=i;k>j;k--)
tab[number][k] = 'X';
The above part of code is informative only..this will check if the move is valid for left side..and if valid convert the opponents pieces.. you need to understand this and put similar logic for "Right", "Diagonal" etc to complete the reversi game.