Why is can't num scan the intended value in c? - c

I have to scan this file which partly contains
SNOL
INTO num IS 8
INTO res IS 9
and the output of the code below is
Program starts...
Set value of num to 0
Set value of res to 8
input msg
which is wrong because num should be 8 and res should be 9
why is it num scanning 0 instead of 8?
and why doesn't the code work anymore if I assign number to num and number to res?
num = number;
//Tokenizer functions//
bool isLowerCase(const char *object)
{
int i;
int len = strlen(object);
for(i = 0; i < len; i++) {
if(object[i] >= 'a' && object[i] <= 'z') {
return true;
}
}
return false;
}
//function to check if character is Float.
bool objectFloat(const char* object) {
//check if 1st character is a digit, if not then return false,
otherwise
return true.
if(!isdigit(object[0]))
return false;
// Check if the 2nd character to the last are digits or periods.
// If not, return false otherwisereturn true
int periods = 0; //initialize how many periods in the object to zero
int i;
//if character is a period then increment periods.
for(i = 1; i < strlen(object); i++) {
if(object[i] == '.') {
periods++;
}
//return false if character is not a digit
else if(!isdigit(object[i])) {
return false;
}
}
// return true if there is only one period.
return periods == 1;
}
//function to check if character is a keyobject.
bool isKeyobject(const char* object) {
char keyobjects[11][11] = { "SNOL", "LONS", "INTO", "IS", "MULT", "BEG",
"PRINT", "ADD", "SUB", "DIV", "MOD" };
int i;
for(i = 0; i < 11; i++) {
// Check if object is equal to keyobjects at index i
// If yes, return true
if(isLowerCase(object))
return false;
if(strcmp(object, keyobjects[i]) == 0) {
return true;
}
}
//object is not equal to any of the keyobjects so return false
return false;
}
//Function to check if every character is an integer
// If not, return false otherwise return true
bool objectInt(const char* object) {
int i;
for(i = 0; i < strlen(object); i++) {
if(!isdigit(object[i])) return false;
}
return true;
}
bool objectIsVariable(const char* object) {
// Check if alphanumeric character & lower case
// If not, return false
int i;
for(i = 0; i < strlen(object); i++) {
if(!isalnum(object[i]) && !isLowerCase(object)) return false;
}
return true;
}
int main() {
FILE *s_path = fopen("test.snol", "r");
int number = 0;
int num, res;
if(isKeyobject(object) && strcmp(object, IsitSNOL) == 0) {
printf("Program starts...\n");
}
else if(isKeyobject(object) && strcmp(object, IsitINTO) == 0) {
printf("Set value of ");
}
if(objectInt(object)) {
number = atoi(object);
}
else if(objectFloat(object)) {
number = atof(object);
}
if(objectIsVariable(object) && strcmp(object, IsitNum) == 0) {
//if float
printf("num to %d\n", number);
num == number;
}
else if(objectIsVariable(object) && strcmp(object, IsitRes) == 0) {
//if float
printf("res to %d\n", number);
res == number;
}
else if(isKeyobject(object) && strcmp(object, IsitBEG) == 0) {
printf("input msg\n");
scanf("%s", msg);
fscanf(s_path, " %s", &object);
printf("INPUT(%s): %s\n", object, msg);
}
}
} // END MAIN -----------------------------------//

The problem seem to be that you read the number after the variable name but you do the print before.
So your sequence is:
Keyobject INTO
objectIsVariable num // Now you print the value
objectInt // Now you read the value
You need to postpone the printing until you have actually read the value.
This is not a very elegant solution, but you can try like:
int flag = 0;
if(objectInt(object)) {
number = atoi(object);
if (flag == 1)
{
num = number;
printf("num to %d\n", number);
}
else if (flag == 2)
{
res = number;
printf("res to %d\n", number);
}
else
{
printf("Illegal flag\n");
}
flag = 0;
}
if(objectIsVariable(object) && strcmp(object, IsitNum) == 0) {
flag = 1;
}
else if(objectIsVariable(object) && strcmp(object, IsitRes) == 0) {
flag = 2;
}

Related

My problem with the size of the number in the My_Mastermind minigame

can you help me with the size of the digits, for example, when I enter 01234, then everything works as it should, but it shouldn’t, the limit of digits should be within four.When I enter some four-digit number, everything works as it should work. But when some five-digit, six-digit or even more, then everything works as if it should be, but it should not work like that. And when I enter numbers that are less than four-digit, for example 123 , then it gives an error and it's good. But when I enter numbers that are more than four digits, it does not give an error and works as if it should be so.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
typedef struct s_mastermind {
int my_attempt;
char* my_code;
} my_mastermind;
my_mastermind* settings_function(my_mastermind* mastermind, int argc, char** argv);
int checking_for_correctness_num(char* _string);
int wrong_input(int progress,char* num_code);
my_mastermind* my_function();
int check_function(char* string);
char* input_function();
int mis_placed_pieces(char* bit, char* num_code);
int well_placed_pieces(char* bit, char* num_code);
int code_checker(char* bit, char* num_code);
char* size_of_function(char* strye);
char* my_strcpy(char* num1, char* num2) {
for(int i = 0; num2[i] != 0; i++) {
num1[i] = num2[i];
}
return num1;
}
int my_strlen(char* num1) {
return (*num1) ? my_strlen(++num1) + 1 : 0;
}
my_mastermind* my_function() {
my_mastermind* num = malloc(sizeof(my_mastermind));
num->my_code = malloc(5);
num->my_code[4] = '\0';
my_strcpy(num->my_code, "");
num->my_attempt = 10;
return num;
}
my_mastermind* settings_function(my_mastermind* mastermind, int argc, char** argv) {
char* bit;
for(int i = 0; i < argc;) {
if (my_strlen(argv[i]) == 2 && argv[i][0] == '-') {
if(argv[i][1] == 'c') {
char* num_code = argv[i + 1];
if(wrong_input(argc,num_code) != 0) {
break;
}
my_strcpy(mastermind->my_code, num_code);
}else if(argv[i][1] == 't') {
if(checking_for_correctness_num(argv[i + 1]) == 0) {
mastermind->my_attempt = check_function(argv[i + 1]);
}
} else {
printf("WRONG FLAG RESTART THE GAME!!!\n");
}
}
i += 1;
}
return mastermind;
}
int wrong_input(int progress,char* num_code) {
// if(my_strlen(num_code) != 4) {
// printf("Code bigger than 4\n");
// }
if(checking_for_correctness_num(num_code) == 1) {
printf("Wrong input!\n> ");
fflush(stdout);
char* code = input_function();
char* variable = size_of_function(code);
free(code);
int results = 1;
if(wrong_input(progress,variable) == 0) {
results = code_checker(num_code, variable);
}
free(variable);
return results;
}
return 0;
}
int checking_for_correctness_num(char* _string) {
for(int i = 0; _string[i] != '\0'; i++) {
if(!(_string[i] >= '0' && _string[i] <= '9')) {
return 1;
}
}
return 0;
}
int check_function(char* string) {
int check_num = 0;
for(int i = 0; string[i] != '\0'; i++) {
check_num = check_num * 10 + (string[i] - '0');
}
return check_num;
}
char* input_function() {
char* getting = malloc(101);
getting[100] = '\0';
read(0, getting, 100);
fflush(stdout);
return getting;
}
int game_progress(int progress, char* bit) {
printf("Round: %d\n> ", progress);
fflush(stdout);
char* code = input_function();
char* variable = size_of_function(code);
free(code);
int results = 1;
if(wrong_input(progress,variable) == 0) {
results = code_checker(bit, variable);
}
free(variable);
return results;
}
void game_action(my_mastermind* mastermind) {
int current_try = 0;
for (;current_try < mastermind->my_attempt;) {
int results = game_progress(current_try, mastermind->my_code);
current_try += 1;
if(results == 0) {
printf("Congratz! You did it!\n");
break;
}
}
}
int code_checker(char* bit, char* num_code) {
int good_w = well_placed_pieces(bit, num_code);
int not_good_m = mis_placed_pieces(bit, num_code);
if(good_w == 3 || good_w == 2 || good_w == 1 || not_good_m == 3 || not_good_m == 2 || not_good_m == 1){
printf("Well placed pieces: %d\nMisplaced pieces: %d\n---\n", good_w,not_good_m);
}
if(good_w == 4) {
return 0;
} else {
return 1;
}
}
int well_placed_pieces(char* bit, char* num_code) {
int number = 0;
for(int i = 0; i < 4; i++) {
if (bit[i] == num_code[i]) {
number += 1;
}
}
return number;
}
int mis_placed_pieces(char* bit, char* num_code) {
int number = 0;
int i = 0;
int j = 0;
while(i < 4) {
i++;
if (bit[i] == num_code[i]) {
number += 1;
}
}
return number;
}
char* size_of_function(char* strye) {
char* new_string = malloc(5);
new_string[4] = '\0';
for(int i = 0; i < 4;i++){
new_string[i] = strye[i];
}
return new_string;
}
int main(int argc, char** argv) {
printf("Will you find the secret code?\n---\n");
my_mastermind* mastermind = my_function();
settings_function(mastermind, argc, argv);
game_action(mastermind);
free(mastermind);
return 0;
}
The problem is that you size_of_function assumes the input string is exactly 4 character long, not counting the '\0'. You should either check if the input string and return a error via a NULL pointer, or fully copy the string and check later.
Returning a NULL pointer require the least modification. You can do it by checking the input string size first :
char* size_of_function(char* strye) {
if(my_strlen(strye) != 4)
return NULL;
char* new_string = malloc(5);
new_string[4] = '\0';
for(int i = 0; i < 4;i++){
new_string[i] = strye[i];
}
if (strye[4] == '\r' || strye[4] == '\n' || strye[4] == '\0')
return new_string;
free(new_string);
return NULL;
}
Then, in wrong_input(), check if num_code is NULL :
int wrong_input(int progress,char* num_code) {
if(num_code == NULL || checking_for_correctness_num(num_code) == 1) {
printf("Wrong input!\n> ");
fflush(stdout);
char* code = input_function();
char* variable = size_of_function(code);
free(code);
int results = 1;
if(wrong_input(progress,variable) == 0) {
results = code_checker(num_code, variable);
}
free(variable);
return results;
}
return 0;
}
It is critical to check if num_code is NULL before calling checking_for_correctness_num(). In C the || operator evaluates the left operand first and skip the second operand evaluation if the first one is true. This way we can ensure that we never pass a NULL pointer to checking_for_correctness_num().
wrong_input() is called recursively and allocates memory without freeing it before calling itself. This can eat up memory fast and is generality considered to be bad practice.
Also, you've implemented my_strlen() as a recursive function, which isn't necessary. Using a loop is better :
int my_strlen(char* num1) {
int index = 0;
while(num1[index++]); //Note that 'index' is post-incremented
return index - 1; //Subtract one to account for the last post increment
}

Why strcmp does not return 0?

I have a small program to handle a list of rabbits (name, district, participation count) stored in an array of pointers (Rabbit** iterator). I'd like to implement the following methods: add, delete and modify a rabbit, list all the rabbits or list by district.
When I compare for example the name of the rabbits in the list with strcmp() it doesn't return 0 when the names are equal. How can I solve this problem?
The Rabbit struct:
typedef struct Rabbit {
char* name;
char* district;
unsigned part_count;
} Rabbit;
The delete method:
bool delete_rabbit(char* delete_name)
{
for (unsigned i = 0; i < size; ++i) {
if (iterator[i] != NULL && strcmp(iterator[i]->name, delete_name) == 0) {
free(iterator[i]);
iterator[i] = NULL;
count--;
return true;
}
}
return false;
}
The list by district method:
void list_by_district(char* district)
{
unsigned counter = 0;
for (unsigned i = 0; i < size; ++i) {
if (iterator[i] != NULL && strcmp(iterator[i]->district, district) == 0) {
counter++;
printf("\n%u. Rabbit:\n", counter);
printf("Name: %s\nDistrict: %s\nParticipation count: %u\n", iterator[i]->name, iterator[i]->district, iterator[i]->part_count);
}
}
}
The modify method is similar to the delete method except it only changes the values.
The corresponding code snippets from main:
Rabbit** iterator;
unsigned size = 10, count = 0;
int main()
{
iterator = (Rabbit**)malloc(sizeof(Rabbit*) * 10);
...
do {
...
switch (input) {
case 'a':
if (count == size) iterator = allocate_more_memory();
...
iterator[count++] = add_rabbit(new_name, new_district, new_part_count);
break;
case 'd':
if (size == count + 6) iterator = allocate_less_memory();
do {
printf("Enter name to be deleted: ");
scanf("%[^\n]", delete_name);
getchar();
if (strlen(delete_name) >= 30) printf("Name only has 30 or less characters!\n");
} while (strlen(delete_name) >= 30);
if (!delete_rabbit(delete_name)) printf("\nThere's no rabbit in the list with this name.\n");
break;
...
}
} while (input != 'x');
...
free(iterator);
return 0;
}
EDIT:
The add method:
Rabbit* add_rabbit(char* new_name, char* new_district, unsigned new_part_count)
{
Rabbit* new_rabbit = (Rabbit*)malloc(sizeof(Rabbit));
if (new_rabbit) {
new_rabbit->name = (char*)malloc((strlen(new_name) + 1) * sizeof(char));
new_rabbit->district = (char*)malloc((strlen(new_district) + 1) * sizeof(char));
strcpy(new_rabbit->name, new_name);
strcpy(new_rabbit->district, district);
new_rabbit->part_count = new_part_count;
}
return new_rabbit;
}
The allocate less memory method:
Rabbit** allocate_less_memory()
{
Rabbit** new_iterator = (Rabbit**)malloc(sizeof(Rabbit*) * (size - 5));
if (new_iterator) {
unsigned counter = 0;
for (unsigned i = 0; i < size; ++i) {
if (iterator[i] != NULL) {
new_iterator[counter++] = iterator[i];
}
}
size -= 5;
free(iterator);
return new_iterator;
}
return NULL;
}

Check if input string is parenthesis completed

I'm trying to write a function, that would check for a matching parentheses.
For example, if the given string is "(1+1))" it would print false otherwise it's true.
However, in my code it's printing false no matter what the case is.
bool isMatched(char pran[]) {
bool completetd = true;
int count = 0;
for (int i = 0; pran[i] != '\0'; i++) {
if (pran[i] == '('){
count++;
}
else {
// It is a closing parenthesis
count--;
}
if (count < 0) {
// there are more Closing parenthesis
completetd = false;
break;
}
// If count is not zero, there are more opening parenthesis
if (count != 0) {
completetd = false;
}
}
return completetd;
}
int main() {
char arr[] = "((1+a))";
if (isMatched(arr)) {
printf("TRUE \n");
}
else {
printf("FALSE \n");
}
return 0;
}
I would appreciate any help.
You can try this not sure if this is what you are looking for.
bool isMatched(char pran[]) {
int open = 0;
int close = 0;
for (int i = 0; pran[i] != '\0'; i++) {
if (pran[i] == '('){
open++;
}
if (pran[i] == ')'){
close++;
}
}
// Check if both match
if(open == close){
return true;
}
return false;
}
int main() {
char arr[] = "((1+a))";
if (isMatched(arr)) {
printf("TRUE \n");
}
else {
printf("FALSE \n");
}
return 0;
}
By adding a
printf("got 1 (!\n"); next to count++;
and a
printf("got 1 )!\n"); next to count--;,
you get:
Got 1 (!
Got 1 (!
Got 1 )!
Got 1 )!
Got 1 )!
FALSE
This shows that you have a validation problem with your checking logic
As pointed-out in the comments, replace your else with else if (pran[i] == ')') { will fix that part for you.
But the real problem lies with your last validation.
Take it out of the for loop. It sets the value to false as soon as you detect a parenthesis.
Thus, take this:
// If count is not zero, there are more opening parenthesis
if (count != 0) {
printf("Count: %d\n",count);
completetd = false;
}
}
and make it this:
}
// If count is not zero, there are more opening parenthesis
if (count != 0) {
printf("Count: %d\n",count);
completetd = false;
}

How to check function return value in an if statement without calling it

I'm trying to check the return value of the function in an if statement so that I will return its value if its 1, but it gets called when I do it in an if statement. Is there a way where I prevent the call in the if statement. I want to check all three function but if I checked one without if statement then it returns 0 and stops.
if (argc != 2)
{
printf("Usage: ./substitution key\n");
return 1;
}
else
{
string chars = argv[1];
if (check_length(chars) == 1)
{
return check_length(chars);
}
else if (check_rc(chars) == 1)
{
return check_rc(chars);
}
else if (check_alpha(chars) == 1)
{
return check_alpha(chars);
}
}
string ptext;
ptext = get_string("Input Text: \n");
}
int check_rc(string chars)
{
for (int i = 0, n = strlen(chars); i < n; i++)
{
for (int j = 0; j < n; j++)
{
if (!(i == j))
{
if (chars[i] == chars[j])
{
printf("Key must not contain repeated characters. \n");
return 1;
}
}
}
}
return 0;
}
int check_alpha(string chars)
{
for (int i = 0, n = strlen(chars); i < n; i++)
{
if (isdigit(chars[i]))
{
printf("Key must only contain alphabetic characters. \n");
return 1;
}
}
return 0;
}
int check_length(string chars)
{
int charLength = strlen(chars);
if( charLength !=26)
{
printf("Key must contain 26 characters.\n");
return 1;
}
return 0;
}
Your Question is hard to understand but i am assuming that if you want to reduce theamount of unnessecary check you could apply the concept of short-circuit evalution of &&
or u could just not use (else if). and use 3 if statement instead.
all following(else if) is skip if one of the if statement before it is true.
hope this help.
You can save the return value in a local variable and use it all the way:
int check_rc_val = check_length(chars);
if (check_rc_val == X)
{
return check_rc_val;
}
int check_rc_val = check_rc(chars);
if (check_rc_val == Y)
{
return check_rc_val;
}
int check_alpha_val = check_alpha(chars);
if (check_alpha_val == Z)
{
return check_alpha_val;
}

Why is my code not working anymore despite working earlier?

My goal is to print
program starts...
set value of num to 0
set value of res to 0
<type in> Bye!!
Input(msg): Bye!!
by implementing the file
SNOL
INTO num IS 0
INTO res IS 0
BEG msg
INTO num IS 5
INTO res IS MULT num num
and this is my code for it.
Question:
I am wondering how my code worked for some time then stopped working when I added some declaration statements.Now I deleted those statements and tried to change it when the code actually worked but now it only works until the scanning of input then after that the program stops.
Additional question:
When I continued to finish my code, I got errors when I tried to evaluate the last statement in the file because I could not figure out how to compare if the number is float or int. After that, the result should be this where res = num*num.
Evaluating MULT: result is 25
bool objectFloat(const char* object){
//check if 1st character is a digit, if not then return false, otherwise return true.
if (!isdigit(object[0]))
return false;
// Check if the 2nd character to the last are digits or periods.
// If not, return false otherwise return true
int periods = 0; //initialize how many periods in the object to zero
int i;
//if character is a period then increment periods.
for(i = 1; i<strlen(object); i++){
if(object[i]=='.'){
periods++;
}
//return false if character is not a digit
else if(!isdigit(object[i])){
return false;
}
}
// return true if there is only one period.
return periods == 1;
}
//function to check if character is a keyobject.
bool isKeyobject(const char* object){
char keyobjects[11][11]= {"SNOL", "LONS", "INTO", "IS", "MULT", "BEG",
"PRINT", "ADD", "SUB", "DIV", "MOD"};
int i;
for(i=0; i<11; i++){
// Check if object is equal to keyobjects at index i
// If yes, return true
if (isLowerCase(object)){
return false;}
if(strcmp(object, keyobjects[i]) == 0){
return true;
}
}
//object is not equal to any of the keyobjects so return false
return false;
}
//Function to check if every character is an integer
// If not, return false otherwise return true
bool objectInt(const char* object){
int i;
for (i = 0; i < strlen(object); i++){
if (!isdigit(object[i])) return false;
}
return true;
}
bool objectIsVariable(const char* object){
// Check if alphanumeric character & lower case
// If not, return false
int i;
for (i = 0; i < strlen(object); i++){
if (!isalnum(object[i])&&!isLowerCase(object)) return false;
}
return true;
}
int setNum(const char* object){
if(objectInt(object)){
int number, num;
number=atoi(object);
num=number;
return num;
}
else if(objectFloat(object)){
float number, num;
number=atof(object);
num=number;
return num;
}
}
int setRes(const char* object){
if(objectInt(object)){
int number, res;
number=atoi(object);
res=number;
return res;
}
else if(objectFloat(object)){
float number, res;
number=atof(object);
res=number;
}
}
int main(){
FILE *s_path = fopen("test.snol", "r");
char object[100];
char msg;
const char* IsitIS = "IS";
const char* IsitMULT = "MULT";
const char* IsitMOD = "MOD";
const char* IsitSNOL= "SNOL";
const char* IsitLONS= "LONS";
const char* IsitINTO = "INTO";
const char* IsitADD= "ADD";
const char* IsitSUB= "SUB";
const char* IsitDIV = "DIV";
const char* IsitBEG = "BEG";
const char* IsitNum = "num";
const char* IsitRes = "res";
int number;
int flag = 0;
// Get each object from s_path until end-of-file is reached
while(fscanf(s_path, "%s", &object) != -1) {
//if it doesn't start with SNOL then end
if (isKeyobject(object)&&strcmp(object, IsitSNOL)==0){
printf ("Program starts...\n\n");
}
else if (isKeyobject(object)&&strcmp(object, IsitINTO)==0){
printf ("...Set value of ");
}
if(objectInt(object)) {
number = atoi(object);
if (flag == 1)
{
setNum(object);
printf("num to %d\n", number);
}
else
{
setRes(object);
printf("res to %d\n", number);
}
}
else if(strcmp(object, IsitNum) == 0) {
flag = 1;
}
else if(strcmp(object, IsitRes) == 0) {
flag = 2;
}
else if(isKeyobject(object)&&strcmp(object, IsitBEG)==0){
printf("input msg\n");
scanf("%s",msg);
fscanf(s_path," %s", &object);
printf ("INPUT(%s): %s\n",object,msg);
}
}
fclose(s_path);
}
I have found the error
I had to change
char msg;
to
char msg[50];
I still need the answer to the additional question though.

Resources