How to simplify large conditional statement - c

This conditional statement compares letters with numbers according to the keyboard of old button-phones.
In this statement, every if-else condition is the same. How can I shorten this piece of code?
//compares every name and pattern character
//every number represents some letters from latin alphabet
if(lowch >= 97 && lowch <= 99 && pattern[ptrch] == '2'){
ptrch++;
mir++;
}
else if(lowch >= 100 && lowch <= 102 && pattern[ptrch] == '3'){
ptrch++;
mir++;
}
else if(lowch >= 103 && lowch <= 105 && pattern[ptrch] == '4'){
ptrch++;
mir++;
}
else if(lowch >= 106 && lowch <= 108 && pattern[ptrch] == '5'){
ptrch++;
mir++;
}
else if(lowch >= 109 && lowch <= 111 && pattern[ptrch] == '6'){
ptrch++;
mir++;
}
else if(lowch >= 112 && lowch <= 115 && pattern[ptrch] == '7'){
ptrch++;
mir++;
}
else if(lowch >= 116 && lowch <= 118 && pattern[ptrch] == '8'){
ptrch++;
mir++;
}
else if(lowch >= 119 && lowch <= 122 && pattern[ptrch] == '9'){
ptrch++;
mir++;
}
else if(lowch == '+' && pattern[ptrch] == '0'){
ptrch++;
mir++;
}
else{
ptrch = 0;
mir = 0;
}
}
**ptrch- pattern char
*mir - matches in a row

Define a macro that encapsulates the comparisons, and then use a single condition with ||.
#define MATCH(start, end, ch) (lowch >= start && lowch <= end && pattern[ptrch] == ch)
if (MATCH('a', 'c', '2') ||
MATCH('d', 'f', '3') ||
MATCH('g', 'i', '4') ||
MATCH('j', 'l', '5') ||
MATCH('m', 'o', '6') ||
MATCH('p', 's', '7') ||
MATCH('t', 'v', '8') ||
MATCH('w', 'z', '9') ||
MATCH('+', '+', '0')) {
ptrch++;
mir++;
} else {
ptrch = 0;
mir = 0;
}
Another option would be to use an array of structures.
struct key {
char start,
char end,
char ch
} keys[] = {
{'a', 'c', '2'},
{'d', 'e', '2'},
...
{'+', '+', '0'}
};
bool found = false;
for (int i = 0; i < sizeof keys/sizeof keys[0]; i++) {
if (lowch >= keys[i].start && lowch <= keys[i].end && pattern[ptrch] == keys[i].ch) {
ptrch++;
mir++;
found = true;
break;
}
if (!found) {
ptrch = 0;
mir = 0;
}

A solution you might consider is to map the letters in an array.
// . . . . . . . . . . abcdefghijklmnopqrstuvwxyz
const char* numbers = "22233344455566677778889999";
char digit = (lowch >= 'a' && lowch <= 'z') ? numbers[lowch - 'a'] : 0;
if (digit == pattern[ptrch]) {
ptrch++;
mir++;
}
else if(lowch == '+' && pattern[ptrch] == '0') {
ptrch++;
mir++;
}
else {
ptrch = mir = 0;
}
Or (slightly overkill) you could build a full table to handle any character...
// Build the table once
char dialpad[1 << CHAR_BIT] = { 0 };
const unsigned char *map_from = "abcdefghijklmnopqrstuvwxyz+";
const char *map_to = "222333444555666777788899990";
for (int i = 0; map_from[i]; i++) dialpad[map_from[i]] = map_to[i];
// Later on...
if (dialpad[(unsigned char)lowch] == pattern[ptrch]) {
ptrch++;
mir++;
}
else {
ptrch = mir = 0;
}

All your characters (except the plus sign) are lower-case letters. In ASCII, these letters are in a contiguous range. You can therefore use an array to map lower-case letters to a number code:
// abcdefghijklmnopqrstuvwxyz
const char code[26] = "22233344455566677778889999";
if (lowch >= 'a' && lowch <= 'z' && code[lowch - 'a'] == pattern[ptrch]) {
ptrch++;
mir++;
} else if (lowch == '+' && pattern[ptrch] == '0') {
ptrch++;
mir++;
} else{
ptrch = 0;
mir = 0;
}
Before accessing the array, you must check whether lowch is a valid lower-case letter. The plus sign must be treated as special case here. (But you could make the array cover the whole 7-bit ASCII range, where the characters that don't have a umber code have a special value, perhaps '\0'.)

Related

Some Errors in my X and O game ( C language)

What I'm trying to do here is a tie toe game, but when my code enters the do - while part, it ends the process by itself. Since I could not solve this part, I did not have a chance to try whether there are other problems with the code, unfortunately, I would be glad if you could help with this issue.
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
char box_area[] = { '0','1','2','3','4','5','6','7','8','9' };
struct Player {
bool turn;
char mark;
int ID;
};
int main()
{
int return_result;
int player_number;
struct Player player1;
struct Player player2;
struct Player users[2];
users[0] = player1;
users[1] = player2;
(player1.mark = 'X') && (player2.mark = 'O');
(player1.turn = true) && (player2.turn = false);
(player1.ID = 1) && (player2.ID = 2);
do
{
box_creat();
for (int i = 0; i < 2; i++) {
if (users[i].turn == true)
{
make_move(users[i].ID);
box_creat();
users[i].turn = false;
users[i + 1].turn = true; \\ I made the logic of this section wrong
\\I will try to fix it, I realized after I sent the question
}
}
return_result = check_the_winner();
} while (return_result == 1 || return_result == -1);
return 0;
}
void box_creat(void) {
printf("| %c | %c | %c |", box_area[0], box_area[1], box_area[2]);
printf("\n\n");
printf("| %c | %c | %c |", box_area[3], box_area[4], box_area[5]);
printf("\n\n");
printf("| %c | %c | %c |", box_area[6], box_area[7], box_area[8]);
}
void make_move(int Player_ID)
{
int choice;
printf("Please select a area between 0-9 ");
scanf("%d", choice);
if (choice == '0' && box_area[0] == '0')
{
if (Player_ID == 1) {
box_area[0] = 'X';
}
else {
box_area[0] = 'O';
}
}
else if (choice == '1' && box_area[1] == '1')
{
if (Player_ID == 1) {
box_area[1] = 'X';
}
else {
box_area[1] = 'O';
}
}
else if (choice == '2' && box_area[2] == '2')
{
if (Player_ID == 1) {
box_area[2] = 'X';
}
else {
box_area[2] = 'O';
}
}
else if (choice == '3' && box_area[3] == '0')
{
if (Player_ID == 1) {
box_area[3] = 'X';
}
else {
box_area[3] = 'O';
}
}
else if (choice == '4' && box_area[4] == '0')
{
if (Player_ID == 1) {
box_area[4] = 'X';
}
else {
box_area[4] = 'O';
}
}
else if (choice == '5' && box_area[5] == '0')
{
if (Player_ID == 1) {
box_area[5] = 'X';
}
else {
box_area[5] = 'O';
}
}
else if (choice == '6' && box_area[6] == '0')
{
if (Player_ID == 1) {
box_area[6] = 'X';
}
else {
box_area[6] = 'O';
}
}
else if (choice == '7' && box_area[7] == '0')
{
if (Player_ID == 1) {
box_area[7] = 'X';
}
else {
box_area[7] = 'O';
}
}
else if (choice == '8' && box_area[8] == '0')
{
if (Player_ID == 1) {
box_area[8] = 'X';
}
else {
box_area[8] = 'O';
}
}
}
int check_the_winner(void)
{
if (box_area[0] && box_area[1] && box_area[2] == 'X' || 'O') {
return 1;
}
else if(box_area[3] && box_area[4] && box_area[5] == 'X' || 'O') {
return 1;
}
else if (box_area[6] && box_area[7] && box_area[8] == 'X' || 'O') {
return 1;
}
else if (box_area[2] && box_area[4] && box_area[6] == 'X' || 'O') {
return 1;
}
else if (box_area[0] && box_area[3] && box_area[6] == 'X' || 'O') {
return 1;
}
else if (box_area[2] && box_area[8] && box_area[5] == 'X' || 'O') {
return 1;
}
else if (box_area[0] && box_area[4] && box_area[8] == 'X' || 'O') {
return 1;
}
else if (box_area[1] && box_area[4] && box_area[7] == 'X' || 'O') {
return 1;
}
else {
return -1;
}
}
I tried out your program and found a few glitches that needed revision as well as adding in some additional bits of code just to neaten things up a bit. Following is your code with those revisions.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
char box_area[] = { '0','1','2','3','4','5','6','7','8','9' };
struct Player
{
bool turn;
char mark;
int ID;
};
void box_creat(void)
{
printf("| %c | %c | %c |", box_area[0], box_area[1], box_area[2]);
printf("\n\n");
printf("| %c | %c | %c |", box_area[3], box_area[4], box_area[5]);
printf("\n\n");
printf("| %c | %c | %c |", box_area[6], box_area[7], box_area[8]);
printf("\n"); /* Added for aesthetics */
}
void make_move(int Player_ID)
{
int choice;
printf("Player %d - please select a area between 0-9 ", Player_ID);
scanf("%d", &choice); /* Corrected missing ampersand */
printf("Player: %d makes a move\n", Player_ID);
if (choice == 0 && box_area[0] == '0') /* FYI - '0' is equivalent to integer value 48 */
{
if (Player_ID == 1)
{
box_area[0] = 'X';
}
else
{
box_area[0] = 'O';
}
}
else if (choice == 1 && box_area[1] == '1')
{
if (Player_ID == 1)
{
box_area[1] = 'X';
}
else
{
box_area[1] = 'O';
}
}
else if (choice == 2 && box_area[2] == '2')
{
if (Player_ID == 1)
{
box_area[2] = 'X';
}
else
{
box_area[2] = 'O';
}
}
else if (choice == 3 && box_area[3] == '3')
{
if (Player_ID == 1)
{
box_area[3] = 'X';
}
else
{
box_area[3] = 'O';
}
}
else if (choice == 4 && box_area[4] == '4')
{
if (Player_ID == 1)
{
box_area[4] = 'X';
}
else
{
box_area[4] = 'O';
}
}
else if (choice == 5 && box_area[5] == '5')
{
if (Player_ID == 1)
{
box_area[5] = 'X';
}
else
{
box_area[5] = 'O';
}
}
else if (choice == 6 && box_area[6] == '6')
{
if (Player_ID == 1)
{
box_area[6] = 'X';
}
else
{
box_area[6] = 'O';
}
}
else if (choice == 7 && box_area[7] == '7')
{
if (Player_ID == 1)
{
box_area[7] = 'X';
}
else
{
box_area[7] = 'O';
}
}
else if (choice == 8 && box_area[8] == '8')
{
if (Player_ID == 1)
{
box_area[8] = 'X';
}
else
{
box_area[8] = 'O';
}
}
}
int check_the_winner(void)
{
if ((box_area[0] == box_area[1]) && (box_area[1] == box_area[2]) && (box_area[0] != '0')) /* Corrected the testing for proper "and" conditioning */
{
return 1;
}
else if ((box_area[3] == box_area[4]) && (box_area[4] == box_area[5]) && (box_area[3] != '3'))
{
return 1;
}
else if ((box_area[6] == box_area[7]) && (box_area[7] == box_area[8]) && (box_area[6] != '6'))
{
return 1;
}
else if ((box_area[2] == box_area[4]) && (box_area[4] == box_area[6]) && (box_area[2] != '2'))
{
return 1;
}
else if ((box_area[0] == box_area[3]) && (box_area[3] == box_area[6]) && (box_area[0] != '0'))
{
return 1;
}
else if ((box_area[2] == box_area[5]) && (box_area[5] == box_area[8]) && (box_area[2] != '2'))
{
return 1;
}
else if ((box_area[0] == box_area[4]) && (box_area[4] == box_area[8]) && (box_area[4] != '4'))
{
return 1;
}
else if ((box_area[1] == box_area[4]) && (box_area[4] == box_area[7]) && (box_area[1] != '1'))
{
return 1;
}
else
{
return -1;
}
}
int main()
{
int return_result;
//int player_number; /* Compiler said that this wasn't being used */
int swap = 1;
int i;
struct Player player1;
struct Player player2;
struct Player *users[2]; /* Used these as address pointers to player "1" and player "2" */
users[0] = &player1; /* Before making these pointers, the users array just contained copies of the player structures */
users[1] = &player2;
(player1.mark = 'X') && (player2.mark = 'O');
(player1.turn = true) && (player2.turn = false);
(player1.ID = 1) && (player2.ID = 2);
do
{
box_creat();
swap += 1;
i = swap % 2;
if (i == 1)
{
make_move(users[1]->ID);
//box_creat(); /* Being performed at the top of the loop */
users[0]->turn = false;
users[1]->turn = true;
}
else
{
make_move(users[0]->ID);
//box_creat();
users[1]->turn = false;
users[0]->turn = true;
}
return_result = check_the_winner();
if (check_the_winner() == 1) /* Added when a winner has been sensed */
{
box_creat();
if (i == 1)
{
printf("Player 2 won!\n");
}
else
{
printf("Player 1 won!\n");
}
}
}
while (return_result != 1);
return 0;
}
I added comments to most of the places I had tweaked, but here are the highlights:
I shuffled some of the functions around so that the "main" function followed all of the helper functions (the compiler was giving warnings about the original sequence of the function positions).
I corrected the "choice" tests as "choice" is an integer, so the test of "choice" needed to be compared to an integer value (e.g. zero) as opposed to character '0' (which actually has a value of 48).
The tests for three letters in a row for either player do not work in that manner. Either a test needed to be made for each box for a certain row needed to tested for an "X" or an "O", and then if that test was true the test needed to be continued for the next box in the row, and then again for the third box in the row. In lieu of that route, the test was revised to basically say "if the character in the first box in the row is the same as the character in the second box in the row, and the character in the second box in the row is the same as the character in the third box in the row, and the first box does not contain a digit character (which means is contains an "X" or an "O"), then there is a winner.
It appears that an attempt was made to mirror the contents of "Player1" and "Player2" into an array of player structures. Although initially, structure "users[0]" contained the same data as "Player1" and structure "users[1]" contained the same data as "Player2", once the data in "Player1" and "Player2" were updated, those changes did to propagate over to the "users" array. So to utilize "users" in the spirit of this program, they were defined as pointers to their respective player structures.
Those were the most significant bits. The other bits were added for a logical conclusion of the game. Note that no logic was added for a draw.
Give that a test and see if that clarifies things and follows the spirit of the project.

My If-statements seem to be ignored even though my variables look fine in the debugger

I just started learning C (I'm an absolute beginner) and I'm trying to make a program that translates Roman numbers to Arabic and vice versa.
If I were to type "IX" my program should give me a "9" as an output but instead I get a "1". I tried to find the issue on my own using the debugger and I can see my program entering the first If-Statement
if (userString[localIndex] == 'I')
but then it skips the inner If-Statement
else if (userString[++localIndex] == 'X') {
ARABIC_NUM += 9;
localIndex++;
}
I'm not sure why this is happening. If I type "IV" my program outputs a "4" which is the correct answer but if I type "IVIV" my programs once again outputs a lonely "4" and ignores the rest of my input.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#define NOT_A_NUMBER 0
#define IS_ROMAN 1
#define IS_ARABIC 2
int ARABIC_NUM = 0;
int findStringLength(char* userString) {
int stringLength = 0;
size_t index = 0;
while (userString[index] != '\0')
{
if (userString[index] != '\0') {
stringLength++;
index++;
}
}
return stringLength;
}
void resetString(char* userString)
{
size_t stringLength = findStringLength(userString);
for (size_t index = 0; index < stringLength; index++)
{
userString[index] = '\0';
}
}
void printString(char* userString)
{
size_t stringLength = findStringLength(userString);
for (size_t index = 0; index < stringLength; index++)
{
if (userString[index] != '\0')
printf("~%zu:%c~ ", index, userString[index]);
else
printf("Null character");
}
}
bool ifEnd(char* numberInput, size_t counter) {
bool userEnd = false;
for (size_t index = 0; index < counter; index++)
{
if ((numberInput[index - 2] == 'E' && numberInput[index - 1] == 'N' && numberInput[index] == 'D')) {
userEnd = true;
}
}
return userEnd;
}
int isNumTrue(char userChar) {
int isRoman = NOT_A_NUMBER;
int isArabic = NOT_A_NUMBER;
if (userChar == 'I' || userChar == 'V' || userChar == 'X' ||
userChar == 'L' || userChar == 'C' || userChar == 'D' || userChar == 'M') {
isRoman = IS_ROMAN;
return isRoman;
}
else if (userChar == '0' || userChar == '1' || userChar == '2' || userChar == '3' || userChar == '4' || userChar == '5' || userChar == '6' || userChar == '7' || userChar == '8' || userChar == '9') {
isArabic = IS_ARABIC;
return isArabic;
}
else {
return NOT_A_NUMBER;
}
}
void convertToArabic(char* userString, size_t counter) {
for (size_t localIndex = 0; userString[localIndex] != '\0'; localIndex++) {
// printf("[ %c%s]", userString[localIndex], "-o ");
if (userString[localIndex] == 'I') {
if (userString[++localIndex] == 'V') {
printf("Made it in");
ARABIC_NUM += 4;
localIndex++;
}
else if (userString[++localIndex] == 'X') {
ARABIC_NUM += 9;
localIndex++;
}
else {
ARABIC_NUM += 1;
}
}
else if (userString[localIndex] == 'V') {
ARABIC_NUM += 5;
}
else if (userString[localIndex] == 'X') {
if (userString[localIndex++] == 'L') {
ARABIC_NUM += 40;
localIndex++;
}
else if (userString[localIndex++] == 'C') {
ARABIC_NUM += 90;
localIndex++;
}
else {
ARABIC_NUM += 10;
}
}
else if (userString[localIndex] == 'L') {
ARABIC_NUM += 50;
}
else if (userString[localIndex] == 'C') {
if (userString[localIndex++] == 'D') {
ARABIC_NUM += 400;
localIndex++;
}
else if (userString[localIndex++] == 'M') {
ARABIC_NUM += 900;
localIndex++;
}
else {
ARABIC_NUM += 100;
}
}
else if (userString[localIndex] == 'D') {
ARABIC_NUM += 500;
}
else if (userString[localIndex] == 'M') {
ARABIC_NUM += 1000;
}
else {
printf("Switch default. You shouldn't be seeing this");
}
/* else
{
printf("[ %c%s]", userString[localIndex],"-x ");
}*/
}
printf("%s%d%s", "\n Number was :", ARABIC_NUM, "\n");
}
bool convertToRoman(char* userString, char* romanStringHolder, size_t counter) {
bool isValid = true;
int arabicNum = atoi(userString);
char repetitionLimit = '\0';
for (size_t index = 0; arabicNum != 0; index++) {
/* if ((isNumTrue(userString[index]) == IS_ARABIC || userString[index] == '\n') && index < counter)
{
printf("[ %c%s]", userString[index], "-o ");
}*/
if (arabicNum >= 4000) {
do {
if (romanStringHolder[index - 2] == romanStringHolder[index - 1] == romanStringHolder[index]) {
repetitionLimit = romanStringHolder[index - 2];
}
if (arabicNum / 1000000 >= 1)//&& repetitionLimit != 'M')
{
romanStringHolder[index] = 'M';
arabicNum -= 1000000;
}
else if (arabicNum / 900000 >= 1)// && repetitionLimit != 'M')
{
romanStringHolder[index] = 'C';
romanStringHolder[++index] = 'M';
arabicNum -= 900000;
}
else if (arabicNum / 500000 >= 1)// && repetitionLimit != 'D')
{
romanStringHolder[index] = 'D';
arabicNum -= 500000;
}
else if (arabicNum / 400000 >= 1)//&& repetitionLimit != 'D')
{
romanStringHolder[index] = 'C';
romanStringHolder[++index] = 'D';
arabicNum -= 400000;
}
else if (arabicNum / 100000 >= 1)// && repetitionLimit != 'C')
{
romanStringHolder[index] = 'C';
arabicNum -= 100000;
}
else if (arabicNum / 90000 >= 1)//&& repetitionLimit != 'C')
{
romanStringHolder[index] = 'X';
romanStringHolder[++index] = 'C';
arabicNum -= 90000;
}
else if (arabicNum / 50000 >= 1)// && repetitionLimit != 'L')
{
romanStringHolder[index] = 'L';
arabicNum -= 50000;
}
else if (arabicNum / 40000 >= 1)// && repetitionLimit != 'L')
{
romanStringHolder[index] = 'X';
romanStringHolder[++index] = 'L';
arabicNum -= 40000;
}
else if (arabicNum / 10000 >= 1)//&& repetitionLimit != 'X')
{
romanStringHolder[index] = 'X';
arabicNum -= 10000;
}
else if (arabicNum / 9000 >= 1)// && repetitionLimit != 'X')
{
romanStringHolder[index] = 'I';
romanStringHolder[++index] = 'X';
arabicNum -= 9000;
}
else if (arabicNum / 5000 >= 1)//&& repetitionLimit != 'V')
{
romanStringHolder[index] = 'V';
arabicNum -= 5000;
}
else if (arabicNum / 4000 >= 1)//&& repetitionLimit != 'I')
{
romanStringHolder[index] = 'I';
romanStringHolder[++index] = 'V';
arabicNum -= 4000;
}
else if (arabicNum / 1000 >= 1)// && repetitionLimit != 'I')
{
romanStringHolder[index] = 'I';
arabicNum -= 1000;
}
index++;
} while (arabicNum >= 4000);
romanStringHolder[index] = '_';
index++;
}
if (arabicNum <= 3999) {
if (arabicNum / 1000 >= 1)
{
romanStringHolder[index] = 'M';
arabicNum -= 1000;
}
if (arabicNum / 900 >= 1)
{
romanStringHolder[index] = 'C';
romanStringHolder[++index] = 'M';
arabicNum -= 900;
}
else if (arabicNum / 500 >= 1)
{
romanStringHolder[index] = 'D';
arabicNum -= 500;
}
else if (arabicNum / 400 >= 1)
{
romanStringHolder[index] = 'C';
romanStringHolder[++index] = 'D';
arabicNum -= 400;
}
else if (arabicNum / 100 >= 1)
{
romanStringHolder[index] = 'C';
arabicNum -= 100;
}
else if (arabicNum / 90 >= 1)
{
romanStringHolder[index] = 'X';
romanStringHolder[++index] = 'C';
arabicNum -= 90;
}
else if (arabicNum / 50 >= 1)
{
romanStringHolder[index] = 'L';
arabicNum -= 50;
}
else if (arabicNum / 40 >= 1)
{
romanStringHolder[index] = 'X';
romanStringHolder[++index] = 'L';
arabicNum -= 40;
}
else if (arabicNum / 10 >= 1)
{
romanStringHolder[index] = 'X';
arabicNum -= 10;
}
else if (arabicNum / 9 >= 1)
{
romanStringHolder[index] = 'I';
romanStringHolder[++index] = 'X';
arabicNum -= 9;
}
else if (arabicNum / 5 >= 1)
{
romanStringHolder[index] = 'V';
arabicNum -= 5;
}
else if (arabicNum / 4 >= 1)
{
romanStringHolder[index] = 'I';
romanStringHolder[++index] = 'V';
arabicNum -= 4;
}
else if (arabicNum / 1 >= 1)
{
romanStringHolder[index] = 'I';
arabicNum -= 1;
}
}
}
if (romanStringHolder > 3999999)
printf("\n");
return isValid;
}
int findNumSystem(char* userString, char* toRomanString) {
//printf(" -%zu and %d-", counter, findStringLength(userString));
size_t counter = findStringLength(userString);
int romanNumAmount = 0;
int arabicNumAmount = 0;
int notNumAmount = 0;
for (size_t localIndex = 0; localIndex < counter; localIndex++) {
if (isNumTrue(userString[localIndex]) == IS_ROMAN || ((isNumTrue(userString[localIndex - 1]) == IS_ROMAN) && (userString[localIndex] == '\n')))
{
printf("[ %c%s]", userString[localIndex], "-R ");
romanNumAmount++;
if (romanNumAmount == (findStringLength(userString) - 1)) {
printf("\nAll Numbers are Roman");
convertToArabic(userString, counter);
break;
}
}
else if (isNumTrue(userString[localIndex]) == IS_ARABIC || ((isNumTrue(userString[localIndex - 1]) == IS_ARABIC) && (userString[localIndex] == '\n')))
{
printf("[ %c%s]", userString[localIndex], "-A ");
arabicNumAmount++;
if (arabicNumAmount == (findStringLength(userString) - 1))
{
printf("\nAll numbers are Arabic");
convertToRoman(userString, toRomanString, counter);
printString(toRomanString);
break;
}
}
else if (isNumTrue(userString[localIndex]) == NOT_A_NUMBER)
{
printf("[ %c%s]", userString[localIndex], "-X ");
notNumAmount++;
if (notNumAmount == (findStringLength(userString))) {
printf("\nNone of the characters is a number of either system");
}
}
}
}
#define LENGTH 1000u
int main() {
typedef char user_Input_Stream;
char lol = '\0';
user_Input_Stream arabToRomanString[LENGTH] = { '\0' };
user_Input_Stream numberInput[LENGTH] = { '\0' };
size_t counter = 0;
bool userEnd = false;
while ((lol != EOF) && (userEnd == false))
{
counter = 0;
printString(&numberInput);
resetString(&numberInput);
resetString(&arabToRomanString);
counter = 0;
printString(&numberInput);
ARABIC_NUM = 0;
printf("\n\n||Beta version, remember to not mix number systems yet||\n");
//Repeats until variable lol countains EOF or until boolean holds a true value
while ((lol != EOF) && (lol != '\n') && (userEnd == false))
{
//gets characters, assigns string with them. Gets rid of newline and stores string in array in uppercase
lol = getchar();
numberInput[counter] = toupper(lol);
userEnd = ifEnd(numberInput, counter);
counter++;
}
//TESTING Travels through String and outputs cells contents. Also, sets boolean to True if user writes END
for (size_t i = 0; i < counter; i++) {
if (numberInput[i] == '\n')
{
lol = '\\';
numberInput[i] = toupper(lol);
}
// printf("| [%zu] = %c |", i, numberInput[i]);
}
findNumSystem(numberInput, arabToRomanString);
printf("\n");
}
printf("\n");
return 0;
}
Does anyone have an idea of what the issue could be? (ARABIC_NUM is a global variable, the name is to make it easier for me to find for now.)
Just in case this might help somebody else, here's the solution I came up with using some of the pointers people in the comment section gave me. It was fairly simple:
I was under the impression that expressions within if-statements don't affect any variables they reference, but in reality they do.
For example: if(userString[localIndex] == 'I' && userString[localIndex++] == 'X')
In the line above, I was expecting the program to check both the current index and the next upcoming index, which it did but the expression userString[localIndex++] within the if-statement also permanently incremented my localIndex variable when I wasn't expecting that change to exist outside of the if-statement's parenthesis. So, my program would check the wrong indexes after the first comparison was made and thus why it gave me the wrong output.
To solve this, I created the variable nextIndex and used it to store the value localIndex +1 meaning it will always represent the index after localIndex. So, It now works as intended.
Below is what my program looks like now. (I moved around the if and if-else statements for better readability but the only changed that solved my predicament was the addition of nextIndex)
void convertToArabic(char* userString, size_t counter) {
size_t nextIndex = 0;
for (size_t localIndex = 0; localIndex < findStringLength(userString); localIndex++) {
// printf("[ %c%s]", userString[localIndex], "-o ");
nextIndex = localIndex+1;
if (userString[localIndex] == 'M') {
ARABIC_NUM += 1000;
}
else if (userString[localIndex] == 'C' && userString[nextIndex] == 'M') {
ARABIC_NUM += 900;
localIndex++;
}
else if (userString[localIndex] == 'D') {
ARABIC_NUM += 500;
}
else if (userString[localIndex] == 'C' && userString[nextIndex] == 'D') {
ARABIC_NUM += 400;
localIndex++;
}
else if(userString[localIndex] == 'C'){
ARABIC_NUM += 100;
}
else if (userString[localIndex] == 'X' && userString[nextIndex] == 'C') {
ARABIC_NUM += 90;
localIndex++;
}
else if (userString[localIndex] == 'L') {
ARABIC_NUM += 50;
}
else if (userString[localIndex] == 'X' && userString[nextIndex] == 'L'){
ARABIC_NUM += 40;
localIndex++;
}
else if (userString[localIndex] == 'X') {
ARABIC_NUM += 10;
}
else if ((userString[localIndex] == 'I') && (userString[nextIndex] == 'X')) {
//localIndex--;
ARABIC_NUM += 9;
localIndex++;
}
else if (userString[localIndex] == 'V') {
ARABIC_NUM += 5;
}
else if ((userString[localIndex] == 'I') && (userString[nextIndex] == 'V')) {
//localIndex--;
printf("Made it in");
ARABIC_NUM += 4;
localIndex++;
}
else if (userString[localIndex] == 'I') {
ARABIC_NUM += 1;
}
/* else
{
printf("[ %c%s]", userString[localIndex],"-x ");
}*/
}
printf("%s%d%s", "\n Number was :", ARABIC_NUM, "\n");
}

I´m making a simple tic-tac-toe game in C and it ends after the first input

I have this problem and I don´t know what´s wrong. The code doesn´t have any errors or warnings but it always take the first if statement of the checkVictory function as correct.
I've tried comparing my code with another one that actually works and it looks identical to me. I´m pretty sure the mistake is in the checkVictory function because I used a variable called flag to check every if statement of the function and my returnValue (which is used as an indicator of my game status) always get triggered by the first if.
Here´s my code... (sorry for the indentation this is my first time using the website)
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
void board();
void markBoard(char mark);
int checkVictory();
int player, choice, flag;
char list[10] = {'-', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
void main() {
int gameStatus;
char mark;
player = 1;
do{
board();
// change turns
player = (player % 2) ? 1 : 2;
//input
printf("Player %d, enter a number: ", player);
scanf("%i", &choice);
// set the correct character based on player turn
mark = (player == 1) ? 'X' : 'O';
markBoard(mark);
gameStatus = checkVictory();
player++;
} while (gameStatus == -1);
if (gameStatus == 1) {
printf("Player %d WIN", --player);
printf("\nflag: %i", flag);
}
else{
printf("Draw");
}
}
void board() {
system("cls");
printf("\n\n\t tic tac toe\n\n");
printf("Player 1 (X) - Player 2 (O)\n\n");
printf(" | | \n");
printf(" %c | %c | %c \n", list[1], list[2], list[3]);
printf("_____|_____|_____\n");
printf(" | | \n");
printf(" %c | %c | %c \n", list[4], list[5], list[6]);
printf("_____|_____|_____\n");
printf(" | | \n");
printf(" %c | %c | %c \n", list[7], list[8], list[9]);
printf(" | | \n");
printf("\n");
}
void markBoard(char mark) {
if (choice == 1 && list[1] == '1')
list[1] = mark;
else if (choice == 2 && list[2] == '2')
list[2] = mark;
else if (choice == 3 && list[3] == '3')
list[3] = mark;
else if (choice == 4 && list[4] == '4')
list[4] = mark;
else if (choice == 5 && list[5] == '5')
list[5] = mark;
else if (choice == 6 && list[6] == '6')
list[6] = mark;
else if (choice == 7 && list[7] == '7')
list[7] = mark;
else if (choice == 8 && list[8] == '8')
list[8] = mark;
else if (choice == 9 && list[9] == '9')
list[9] = mark;
else {
printf("Invalid move\n");
player--;
getch();
}
}
/*********************************************FUNCTION TO RETURN GAME STATUS1 FOR GAME IS OVER WITH RESULT-1 FOR GAME IS IN PROGRESSO GAME IS OVER AND NO RESULT**********************************************/
int checkVictory() {
int returnValue = 0;
if (list[1] && list[2] == list[2] && list[3]) {
returnValue = 1;
flag = 1;
}
else if (list[4] && list[5] == list[5] && list[6]) {
returnValue = 1;
flag = 2;
}
else if (list[7] && list[8] == list[8] && list[9]) {
returnValue = 1;
flag = 3;
}
else if (list[1] && list[4] == list[4] && list[7]) {
returnValue = 1;
flag = 4;
}
else if (list[2] && list[5] == list[5] && list[8]) {
returnValue = 1;
flag = 5;
}
else if (list[3] && list[6] == list[6] && list[9]) {
returnValue = 1;
flag = 6;
}
else if (list[1] && list[5] == list[5] && list[9]) {
returnValue = 1;
flag = 7;
}
else if (list[3] && list[5] == list[5] && list[7]) {
returnValue = 1;
flag = 8;
}
else if (list[1] != '1' && list[2] != '2' && list[3] != '3' &&
list[4] != '4' && list[5] != '5' && list[6] != '6' &&
list[7] != '7' && list[8] != '8' && list[9] != '9') {
returnValue = 0;
}
else
returnValue = -1;
return returnValue;
}
The problem lies with the code below.
if (list[1] && list[2] == list[2] && list[3]) {
returnValue = 1;
Your condition:
list[1] && list[2] == list[2] && list[3]
Parses as:
list[1] && (list[2] == list[2]) && list[3]
Because no element of list is 0, they all test as true. Likewise, list[2] will always be equal to itself. Consequently this condition is always true. checkVictory will always return 1. When this is called, and gameSttatus is set to 1, the do-while loop ends.

Function only returning return value it is not supposed to reach

I am working on a project for a programming class, where the goal is to verify a strength of a password based on different security levels. My problem is that with 2nd level, the:
Counter of numbers and special characters isn't working properly and isn't detecting numbers (it was working before I put it in its own function), but more importantly, the function only returns the value set in the very end. I have no idea what else to try.
int level2() {
while ((fgets(given_string, 100, stdin) != NULL)) {
for (int i = 0; given_string[i] != '\n'; i++) {
if (given_string[i] >= 'a' && given_string[i] <= 'z') {
lowerCaseLetterFound++;
} else if (given_string[i] >= 'A' && given_string[i] <= 'Z') {
upperCaseLetterFound++;
} else if (given_string[i] >= '0' && given_string[i] <= '9') {
numberFound++;
} else {
specialCharacterFound++;
}
}
}
printf("%d %d %d %d\n", lowerCaseLetterFound, upperCaseLetterFound, numberFound, specialCharacterFound);
if (param == 1 || param == 2) {
if (lowerCaseLetterFound >= 1 && upperCaseLetterFound >= 1) {
return 1;
} else {
return 0;
}
} else if (param == 3) {
if (((lowerCaseLetterFound >= 1 && upperCaseLetterFound >= 1) && numberFound >= 1) ||
((lowerCaseLetterFound >= 1 && upperCaseLetterFound >= 1) && specialCharacterFound >= 1)) {
return 1;
} else {
return 0;
}
} else if (param >= 4) {
if (lowerCaseLetterFound >= 1 && upperCaseLetterFound >= 1 && numberFound >= 1 &&
specialCharacterFound >= 1) {
return 1;
} else {
return 0;
}
}
return 0;
}
PS: This is my first time asking question here, and I am a programming newbie. Thanks for your help.
Update: Adding the whole code as I have it RN.
char given_string[100];
int lowerCaseLetterFound = 0;
int upperCaseLetterFound = 0;
int numberFound = 0;
int specialCharacterFound = 0;
int repeatedCharacter = 0;
int param;
int level;
int level1 () {
while ((fgets(given_string, 100, stdin) != NULL)) {
for (int i = 0; given_string[i] != '\n'; i++) {
if (given_string[i] >= 'a' && given_string[i] <= 'z') {
lowerCaseLetterFound++;
} else if (given_string[i] >= 'A' && given_string[i] <= 'Z') {
upperCaseLetterFound++;
}
}
}
if (lowerCaseLetterFound >= 1 && upperCaseLetterFound >= 1) {
return 1;
} else {
return 0;
}
}
int level2() {
while ((fgets(given_string, 100, stdin) != NULL)) {
for (int i = 0; given_string[i] != '\n'; i++) {
if (given_string[i] >= 'a' && given_string[i] <= 'z') {
lowerCaseLetterFound++;
} else if (given_string[i] >= 'A' && given_string[i] <= 'Z') {
upperCaseLetterFound++;
} else if (given_string[i] >= '0' && given_string[i] <= '9') {
numberFound++;
} else {
specialCharacterFound++;
}
}
}
printf("%d %d %d %d\n", lowerCaseLetterFound, upperCaseLetterFound, numberFound, specialCharacterFound);
if (param == 1 || param == 2) {
if (lowerCaseLetterFound >= 1 && upperCaseLetterFound >= 1) {
return 1;
} else {
return 0;
}
} else if (param == 3) {
if (((lowerCaseLetterFound >= 1 && upperCaseLetterFound >= 1) && numberFound >= 1) ||
((lowerCaseLetterFound >= 1 && upperCaseLetterFound >= 1) && specialCharacterFound >= 1)) {
return 1;
} else {
return 0;
}
} else if (param >= 4) {
if (lowerCaseLetterFound >= 1 && upperCaseLetterFound >= 1 && numberFound >= 1 &&
specialCharacterFound >= 1) {
return 1;
} else {
return 0;
}
}
return 0;
}
/*
int level3() {
while ((fgets(given_string, 100, stdin) != NULL)) {
for (int i = 0; given_string[i] != '\n'; i++) {
if (given_string[i] >= 'a' && given_string[i] <= 'z') {
lowerCaseLetterFound++;
} else if (given_string[i] >= 'A' && given_string[i] <= 'Z') {
upperCaseLetterFound++;
} else if (given_string[i] >= '0' && given_string[i] <= '9') {
numberFound++;
} else {
specialCharacterFound++;
}
}
}
}
*/
int main(int argc, const char *argv[]) {
//ukládám argumenty, prozatím pouze 2 ze 3
if (argc <= 1) {
printf("Not enough arguments provided. Please, provide LEVEL and PARAM arugments.\n");
} else if (argc >= 5) {
printf("Too many arguments provided.\n");
}
int level = atoi(argv[1]);
int param = atoi(argv[2]);
if (level <= 0 || level >= 5) {
printf("Level must be 1 through 4.\n");
}
if (param <= 0) {
printf("Parameter is not a full positive number.\n");
}
//vyhodnocování na základě zadaných parametrů - kontrola
//LEVEL = 1
if (level == 1) {
level1();
if (level1() == 1) {
printf("Password passed check 1.\n");
} else {
printf("Password did not pass check 1.\n");
}
}
if (level == 2) {
if (level1() == 1) {
if (level2() == 1) {
printf("Password did pass the check.\n");
}
} else {
printf("Password did not pass the check.\n");
}
if (level1() == 0) {
printf("Password did not pass the check.\n");
}
}
if (level == 3) {
}
}
Try to put your code in more than one function.
I think you can't print sth in your function. You should return just one thing you want to get from your function and then in another function, get input the first function's return.
It looks like the problem is that you’re re-defining your global variables in your main function. For example, when you do int param = atoi(argv[2]); in your main, param is scoped to your main. As soon as you leave your main function, you will be accessing the global param which has never been set.
You can either remove the variable type in your main so you are setting the global variables:
param = atoi(argv[2]);
Or get rid of the global variables and pass the ones created in main to any function that needs them.

How do I handle the newline, and separator spacing in c?

The actual text file is just random stuff to test the lex and parse. The pic above is the result, the console is giving me during runtime. In the green it is calling an Identifier when it should be a newline or delim, so nothing should be needed. In the red it is not recognizing the separator, and in the yellow its not reading the something.something at all. I'm assuming it has something to do with with the previous c; not being seperated right.
So my question is how do I properly separate the tokens, and recognize the newline, or what am I doing wrong. Below is the code that I am using to do the separating and tokenizing.
#define _CRT_SECURE_NO_WARNINGS
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BUFFER_SIZE 1024
// Returns 'true' if the character is a DELIMITER.
bool isDelimiter(char ch)
{
if (isspace (ch))
return (true);
return (false);
}
// Returns 'true' if the character is a SEPERATOR.
bool isSeperator(char str)
{
if (str == ',' || str == ';' || str == '>' ||
str == '<' || str == '(' || str == ')' || str == '[' || str == ']' ||
str == '{' || str == '}' || str == '.' )
return (true);
return (false);
}
// Returns 'true' if the character is an OPERATOR.
bool isOperator(char ch)
{
if (ch == '+' || ch == '-' || ch == '*' ||
ch == '/' || ch == '>' || ch == '<' ||
ch == '=')
return (true);
return (false);
}
// Returns 'true' if the string is a VALID IDENTIFIER.
bool validIdentifier(char* str)
{
if (str[0] == '0' || str[0] == '1' || str[0] == '2' ||
str[0] == '3' || str[0] == '4' || str[0] == '5' ||
str[0] == '6' || str[0] == '7' || str[0] == '8' ||
str[0] == '9' )
return (false);
return (true);
}
// Returns 'true' if the string is a KEYWORD.
bool isKeyword(char* str)
{
if (!strcmp(str, "if") || !strcmp(str, "else") ||
!strcmp(str, "while") || !strcmp(str, "do") ||
!strcmp(str, "break") || !strcmp(str, "elem") ||
!strcmp(str, "lout") || !strcmp(str, "file") ||
!strcmp(str, "console") || !strcmp(str, "read") ||
!strcmp(str, "write") || !strcmp(str, "mark") ||
!strcmp(str, "emblemnize") || !strcmp(str, "lin") ||
!strcmp(str, "send") || !strcmp(str, "dint") ||
!strcmp(str, "continue") || !strcmp(str, "int")
|| !strcmp(str, "double") || !strcmp(str, "float")
|| !strcmp(str, "return") || !strcmp(str, "char")
|| !strcmp(str, "case") || !strcmp(str, "char")
|| !strcmp(str, "sizeof") || !strcmp(str, "long")
|| !strcmp(str, "short") || !strcmp(str, "typedef")
|| !strcmp(str, "switch") || !strcmp(str, "unsigned")
|| !strcmp(str, "void") || !strcmp(str, "static")
|| !strcmp(str, "struct") || !strcmp(str, "goto"))
return (true);
return (false);
}
// Returns 'true' if the string is an INTEGER.
bool isInteger(char* str)
{
int i, len = strlen(str);
if (len == 0)
return (false);
for (i = 0; i < len; i++) {
if (str[i] != '0' && str[i] != '1' && str[i] != '2'
&& str[i] != '3' && str[i] != '4' && str[i] != '5'
&& str[i] != '6' && str[i] != '7' && str[i] != '8'
&& str[i] != '9' || (str[i] == '-' && i > 0))
return (false);
}
return (true);
}
// Returns 'true' if the string is a REAL NUMBER.
bool isRealNumber(char* str)
{
int i, len = strlen(str);
bool hasDecimal = false;
if (len == 0)
return (false);
for (i = 0; i < len; i++) {
if (str[i] != '0' && str[i] != '1' && str[i] != '2'
&& str[i] != '3' && str[i] != '4' && str[i] != '5'
&& str[i] != '6' && str[i] != '7' && str[i] != '8'
&& str[i] != '9' && str[i] != '.' ||
(str[i] == '-' && i > 0))
return (false);
if (str[i] == '.')
hasDecimal = true;
}
return (hasDecimal);
}
// Extracts the SUBSTRING.
char* subString(char* str, int left, int right)
{
int i;
char* subStr = (char*)malloc(sizeof(char) * (right - left + 2));
for (i = left; i <= right; i++)
subStr[i - left] = str[i];
subStr[right - left + 1] = '\0';
return (subStr);
}
// Parsing the input STRING.
void parse(char* str)
{
int left = 0, right = 0;
int len = strlen(str);
while (right <= len && left <= right)
{
if (isDelimiter(str[right]) == false)
right++;
if (isDelimiter(str[right]) == true && left == right)
{
if (isOperator(str[right]) == true)
printf("'%c' IS A OPERATOR\n", str[right]);
right++;
left = right;
}
if (isDelimiter(str[right]) == true && left == right)
{
if (isDelimiter(str[right]) == true)
printf("'%c' IS A DELIMITER\n", str[right]);
right++;
left = right;
}
if (isSeperator(str[right]) == true && left == right)
{
//needed to recognize seperator to the right
if (isSeperator(str[right]) == true)
printf("'%c' IS A SEPERATOR\n", str[right]);
right++;
left = right;
//needed to recognize seperator to the left
if (isSeperator(str[right]) == true)
printf("'%c' IS A SEPERATOR\n", str[left]);
right++;
left = right;
}
else if (isDelimiter(str[right]) == true && left != right
|| (right == len && left != right)) {
char* subStr = subString(str, left, right - 1);
if (isKeyword(subStr) == true)
printf("'%s' IS A KEYWORD\n", subStr);
else if (isInteger(subStr) == true)
printf("'%s' IS AN INTEGER\n", subStr);
else if (isRealNumber(subStr) == true)
printf("'%s' IS A REAL NUMBER\n", subStr);
else if (validIdentifier(subStr) == true
&& isDelimiter(str[right - 1]) == false
&& isSeperator(str[right - 1]) == false)
printf("'%s' IS A VALID IDENTIFIER\n", subStr);
left = right;
}
}
return;
}
int main(int argc, char *argv)
{
/* declare a file pointer */
FILE *file;
char *buffer;
long numbytes;
/* open an existing file for reading */
file = fopen("Text.txt", "r");
/* quit if the file does not exist */
if (file == NULL)
return 1;
/* Get the number of bytes */
fseek(file, 0L, SEEK_END);
numbytes = ftell(file);
/* reset the file position indicator to
the beginning of the file */
fseek(file, 0L, SEEK_SET);
/* grab sufficient memory for the
buffer to hold the text */
buffer = (char*)calloc(numbytes, sizeof(char));
/* memory error */
if (buffer == NULL)
return 1;
/* copy all the text into the buffer */
fread(buffer, sizeof(char), numbytes, file);
/* confirm we have read the file by
outputing it to the console */
printf(" The file called Text.txt contains this text \n \n %s \n\n", buffer);
parse(buffer); // calling the parse function
fclose(file);
/* free the memory we used for the buffer */
free(buffer);
return 0;
}
Looks like the problem is your isDelimiter function isn't picking up all possible values. If you change it to use isspace() it will match on all forms of whitespace.
bool isDelimiter(char ch)
{
if (isspace(ch))
return (true);
return (false);
}
As an example, here is a very simple state machine to give you an idea of what sort of thing I meant. It can be in either of one of two states - INSIDE_IDENTIFIER or OUTSIDE_IDENTIFIER - and it switches between those two states depending on what kind of character it is looking at.
#define OUTSIDE_IDENTIFIER (0)
#define INSIDE_IDENTIFIER (1)
void parse(char *str)
{
char *ch;
int state=OUTSIDE_IDENTIFIER;
char buffer[1000];
char *pos=buffer;
for(ch=str;*ch!='\0';ch++)
{
switch(state)
{
case INSIDE_IDENTIFIER:
if(isOperator(*ch))
{
*pos='\0';
printf("Identifier[%s]\n",buffer);
printf("Operator[%c]\n",*ch);
state=OUTSIDE_IDENTIFIER;
}
else if(isDelimiter(*ch))
{
*pos='\0';
printf("Identifier[%s]\n",buffer);
printf("Delimiter[%c]\n",*ch);
state=OUTSIDE_IDENTIFIER;
}
else if(isspace(*ch))
{
*pos='\0';
printf("Identifier[%s]\n",buffer);
printf("Space[%d]\n",*ch);
state=OUTSIDE_IDENTIFIER;
}
else
{
*pos=*ch;
pos++;
}
break;
case OUTSIDE_IDENTIFIER:
default:
if(isOperator(*ch))
{
printf("Operator[%c]\n",*ch);
}
else if(isDelimiter(*ch))
{
printf("Delimiter[%c]\n",*ch);
}
else if(isSeperator(*ch))
{
printf("Seperator[%c]\n",*ch);
}
else
{
state = INSIDE_IDENTIFIER;
pos=buffer;
*pos=*ch;
pos++;
}
break;
}
}
}

Resources