How can I fix the If and structure problem in C? - c

My program should ask user for last full moon date, check if data is correct and then ask user does he want to see dates of next or previouse full moons and how many. I have some problems with "if"and "else if". I don't know why but program basiclly acts like it doesn't see that user gave anything in this line scanf_s("%s", &czy_kolejne); and goes straight to else{printf("\nBłędny znak."); }. I'm also not sure if structure for date is the best way to do it, becasue it have some problem with previouse dates. Could someone give me any advice ?
#include<time.h>
#include<stdlib.h>
int main()
{
int rok, miesiac, dzien;
char czy_kolejne;
int kolejne_pelnie;
int poprzednie_pelnie;
printf_s("Kiedy byla ostatnia pelnia ? (DD.MM.YYYY): ");
scanf_s("%d.%d.%d", &dzien, &miesiac, &rok);
if (rok >= 0)
{
if (miesiac >= 1 && miesiac <= 12)
{
if ((dzien >= 1 && dzien <= 31) && (miesiac == 1 || miesiac == 3 || miesiac == 5 || miesiac == 7 || miesiac == 8))
{
printf_s("Poprawna data. %d.%02d.%d", dzien, miesiac, rok);
}
else if ((dzien >= 1 && dzien <= 31) && (miesiac == 10 || miesiac == 12))
{
printf_s("Poprawna data. %d.%d.%d", dzien, miesiac, rok);
}
else if ((dzien >= 1 && dzien <= 30) && (miesiac == 4 || miesiac == 6 || miesiac == 9))
{
printf_s("Poprawna data. %d.%02d.%d", dzien, miesiac, rok);
}
else if ((dzien >= 1 && dzien <= 30) && miesiac == 11)
{
printf_s("Poprawna data. %d.%d.%d", dzien, miesiac, rok);
}
else if ((dzien >= 1 && dzien <= 28) && miesiac == 2)
{
printf_s("Poprawna data. %d.%02d.%d", dzien, miesiac, rok);
}
else if (dzien == 29 && miesiac == 2 && (rok % 400 == 0 || (rok % 4 == 0 && rok % 100 != 0)))
{
printf_s("Poprawna data. %d.%02d.%d", dzien, miesiac, rok);
}
else
{
printf_s("Liczba dni w miesiacu jest bledna.");
}
}
else
{
printf_s("Nie ma tylu miesiecy.");
}
}
struct tm t = { 0 };
t.tm_mday = dzien;
t.tm_mon = miesiac - 1;
t.tm_year = rok - 1900;
int skip = 29;
t.tm_mday += skip;
mktime(&t);
char buffer[30];
printf("\nCzy wyliczyc daty kolejnych pelni ? (T/N)");
scanf_s("%s", &czy_kolejne); //The problem starts right here.//
if ((czy_kolejne=='t') || (czy_kolejne=='T'))
{
printf_s("\nIle dat w przod?");
scanf_s("%d", &kolejne_pelnie);
for (int i = 1; i <= kolejne_pelnie; i++)
{
int skip = 29 * i;
t.tm_mday += skip;
strftime(buffer, 30, "\n%d-%m-%Y", &t);
puts(buffer);
}
}
else if ((czy_kolejne=='n') || (czy_kolejne=='N'))
{
printf_s("\nIle dat w tył wyliczyc?");
scanf_s("%d", &poprzednie_pelnie);
for (int i= 1; i <= poprzednie_pelnie; i++)
{
int skip = 29 * i;
t.tm_mday -= skip;
strftime(buffer, 30, "\n%d.%m.%Y", &t);
puts(buffer);
}
}
else
{
printf("\nBłędny znak.");
}
return 0;
}

At least two things are wrong with scanf_s("%s", &czy_kolejne), when czy_kolejne is of datatype char:
First, %s will read in a 0-terminated string, but you provide a buffer of type char; this is undefined behaviour, very likely just corrupting memory and leading to weird results. For reading in exactly one character use format "%c".
Second, if you make czy_kolejne to a char array, e.g. char czy_kolejne[10], then scanf_s with a format %sis OK, but it requires an additional argument indicating the buffer size. I.e. you'd have to write scanf_s("%s", &czy_kolejne, sizeof(czy_kolejne)).

Related

`else if` condition not properly working in my program in c

I am new and I don't know to to resolve this error.
When I give inputs for the third else if statement condition it gives the output as salary =0.
Can anyone explain why this happening?
I want to get the answer as :the salary of the candidate = 7000
but the output shows as : the salary of the candidate = 0
/******************* calculating the salary *********************/
/***** bitwise operator ***********/
#include <stdio.h>
int main()
{
char gen;
int qual, y_o_s, sal = 0 ;
printf ( "Enter Gender, Years of Service and Qualifications ( 0 = G, 1 = PG ):\n" );
printf("enter the gen, y_o_s, qual, \n");
scanf("%c\n%d\n%d", &gen, &y_o_s, &qual);
if (gen == 'M' && y_o_s >= 10 && qual == 1)
sal = 15000;
else if ((gen == 'M' && y_o_s >= 10 && qual == 0) ||
(gen = 'M' && y_o_s < 10 && qual == 1))
sal = 10000;
else if (gen == 'M' && y_o_s < 10 && qual == 0)
sal = 7000;
else if (gen == 'F' && y_o_s >= 10 && qual == 1)
sal= 12000;
else if (gen == 'F' && y_o_s >= 10 && qual == 0)
sal = 9000;
else if (gen == 'F' && y_o_s < 10 && qual == 1)
sal = 10000;
else if (gen == 'F' && y_o_s >= 10 && qual == 0)
sal = 6000;
printf("the salary of the candidat = %d\n", sal);
return 0;
}
I want to get the answer as :the salary of the candidate = 7000
but the output shows as : the salary of the candidate = 0.
Alter your if-else-if ladder like :
#define POST_GRAD 1
#define SEX_MALE 'M'
if (SEX_MALE == gen) {
if (POST_GRAD == qual) {
sal = (y_o_s >= 10) ? 15000 : 10000;
} else { // undergrad
sal = (y_o_s >= 10) ? 10000 : 7000;
}
} else { // not Male
if (POST_GRAD == qual) {
sal = (y_o_s >= 10) ? 12000 : 10000;
} else { // undergrad
sal = (y_o_s >= 10) ? 9000 : 6000;
}
}
It's easier to follow. Notice, that constants like POST_GRAD are on the left side comparator ==, it helps compiler catch unintended typos like = for comparisons.
Also, you may want those salaries at one place like :
#define MALE_PG_EXP_SAL 15000
#define MALE_UG_EXP_SAL 10000
// and so on
#define FEMALE_UG_EXP_SAL 9000
#define FEMALE_UG_INEXP_SAL 6000
When they change, you can find them at one place to modify.
PS: I wouldn't want to work at this place.
You are assigning a value to gen
else if ((gen == 'M' && y_o_s >= 10 && qual == 0) ||
(gen = 'M' && y_o_s < 10 && qual == 1))
^
So when you get to your next line gen is no longer what you expect.
else if (gen == 'M' && y_o_s < 10 && qual == 0)
^^
And then improve the code with SparKots suggestions.

How to make conditional statements more compact in C?

I have a code snippet that uses if-else if-else block. I am wondering any potential ways to shorten the lengthy conditional statement else if (cardLength == 16) && (numberArray[0] == 5 && (numberArray[1] == 1 || numberArray[1] == 2 || numberArray[1] == 3 || numberArray[1] == 4 || numberArray[1] == 5)), for instance, without changing the logic. In python, I can do in this way: if (cardLength == 16) and (numberArray[0:2] in range(51,56)). Are there any specific syntax sugar that I can use fo this purpose in C?
if (cardLength == 15) &&
(numberArray[0] == 3 && (numberArray[1] == 4 || numberArray[1] == 7))
{
printf("AMEX\n");
}
else if (cardLength == 16) &&
(numberArray[0] == 5 && (numberArray[1] == 1 || numberArray[1] == 2 || numberArray[1] == 3 || numberArray[1] == 4 || numberArray[1] == 5))
{
printf("MASTERCARD\n");
}
else if (cardLength == 13) && (numberArray[0] == 4)
{
printf("VISA\n");
}
else
{
printf("INVALID\n");
}
Put it into a (static) function. Dont think about performance/optimisation yet.
static char *card_leng_type2string( unsigned len, int *arr)
{
if (len == 15 && arr[0] == 3 && arr[1] == 4 ) return "AMEX";
if (len == 15 && arr[0] == 3 && arr[1] == 7 ) return "AMEX";
if (len == 16 && arr[0] == 5 && arr[1] == 1 ) return "MASTERCARD";
if (len == 16 && arr[0] == 5 && arr[1] == 2 ) return "MASTERCARD";
if (len == 16 && arr[0] == 5 && arr[1] == 3 ) return "MASTERCARD";
if (len == 16 && arr[0] == 5 && arr[1] == 4 ) return "MASTERCARD";
if (len == 16 && arr[0] == 5 && arr[1] == 5 ) return "MASTERCARD";
if (len == 13 && arr[0] == 4) return "VISA";
return "INVALID";
}
Now your calling code could just do:
printf("%s\n", card_leng_type2string(cardLength, numberArray) );
You could convert the first two digits of the numberArray into a new number like this
num = numberArray[0]*10 + numberArray[1]
and then use that into the conditional statements to make them more readable
int num = numberArray[0]*10 + numberArray[1]
if ((cardLength == 15) && ((num == 37) || (num == 34)))
{
printf("AMEX\n");
}
else if ((cardLength == 16) && ((num >= 51) && (num <= 55)))
{
printf("MASTERCARD\n");
}
else if ((cardLength == 13) && ((num >= 40) && (num <= 49)))
{
printf("VISA\n");
}
else
{
printf("INVALID\n");
}
return 0;
}
Assuming that entries in numberArray are in range 0-9, you could use strchr function. This returns non-NULL if a given string contains a specific character.
Replace:
numberArray[1] == 4 || numberArray[1] == 7 || numberArray[1] == 9
with
strchr("479", '0' + numberArray[1])
If numberArray was an array of character then the check could be simplified to strchr("479", numberArray[1])
If you want the logic intact and only want modification for readbility, you could try adding a preprocessor directive gloabally.
This would replace the text or inline function anywhere you use it in the program.
Example
#define AMEX_CONDITION (cardLength == 15) && (numberArray[0] == 3 && (numberArray[1] == 4 || numberArray[1] == 7))
and use it in your if as
if(AMEX_CONDITION){
printf("AMEX");
}

How to check if date is valid using mktime in C?

I have a little problem with my code. I need to check if user's given date is valid or not. I want to check it using 2 rules:
1. Date is valid date and found in a calendar (for example 29.2.2015 is invalid because there's only 28 days in February 2015) 2. Day and month can only be max 2 numbers (for example day 10 and 02 are valid but 010 and 002 are not). All help is appreciated!
This is my code this far:
void dateValidator(const char *date1) {
struct tm date = {0};
int day1;
int month1;
int year1;
int vday;
int vmonth;
int vyear;
sscanf(date1, "%3d.%3d.%d",&day1,&month1,&year1);
/**How do I check that if sscanf reads more than 2 characters on month and day, date is
invalid?**/
date.tm_year = year1 - 1900;
date.tm_mon = month1 - 1;
date.tm_mday = day1;
date.tm_isdst = -1;
vday = date.tm_mday;
vmonth = date.tm_mon;
vyear = date.tm_year;
mktime(&pvm);
if ((vday != date.tm_mday) || (vmonth != date.tm_mon) || (vyear != date.tm_year)) {
/**This doesnt seem to work**/
printf("Invalid date");
}
}
I have deleted my previous answer and posting another one. Actually your code is fine, You just have to send the correct parameter to mktime and to check its return value. I.e. change:
mktime(&pvm);
if ((vday != date.tm_mday) || (vmonth != date.tm_mon) || (vyear != date.tm_year)) {
/**This doesnt seem to work**/
printf("Invalid date");
}
to something like:
r = mktime(&date);
if (r == -1 || (vday != date.tm_mday) || (vmonth != date.tm_mon) || (vyear != date.tm_year)) {
printf("Invalid date");
}
and declare the variable r as time_t r;.
int IsValidDate(int year, int month, int day)
{
unsigned int leap;
unsigned char mon_day[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
/* check the rang of the year */
if ((year < 1) || (year >= 3200))
{
return 0;
}
if ((month < 1) || (month > 12))
{
return 0;
}
/* if it's leep year */
if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
{
leap = 1;
}
else
{
leap = 0;
}
mon_day[1] += leap;
if ((day > mon_day[month - 1]) || (day < 1))
{
return 0;
}
return 1;
}
For ruler 1, I have wrote this code for check the date before.
And I hope this code can help you.
The ruler 2 can easily checked, you can check it by format the valid date and compare it with the input string.
How do I check that if sscanf reads more than 2 characters on month and day, date is invalid?
Day and month can only be max 2 numbers digits (for example day 10 and 02 are valid but 010 and 002 are not).
An easy check: Record the offset at the end of the scan and tests 1) that it is not the original 0 (scanning got that far) and 2) this is the end of the string so as to detect extra junk in data1[]. Change 3d to 2d.
int n = 0;
sscanf(date1, "%2d.%2d.%d %n",&day1,&month1,&year1, &n);
if (n > 0 && data1[n] == '\0') Success();
else Fail();
Pedantic code would check with "%[]" to disallow leading spaces and '+'.
int n = 0;
sscanf(date1, "%*2[0-9].%*2[0-9].%*4[0-9] %n", &n);
if (n == 0 || data1[n]) Fail();
else {
sscanf(date1, "%2d.%2d.%d",&day1,&month1,&year1);
...
How to check if date is valid using mktime?
#Marian posted a good solution which adds a test of the return value of mktime().
if (-1 == mktime(&data)) Fail();
if (vday != date.tm_mday) || (vmonth != date.tm_mon) || (vyear != date.tm_year) Fail();

If else statement troubles in C

I am trying to input a seat number of "15" into this function and get the char value of 'A'. However, for some reason every time I input a number that should be a type 'A'(because its remainder doesn't equal any of the aforementioned values) it gets stuck in the 'M' else if statement. I really do not understand why and would like some help if you have time :)
char whatTypeOfSeat(int seatNumber){
if((seatNumber % 6) == 0 || seatNumber % 6 == 1 || seatNumber == 1) {
typeOfSeat = 'W';
}
else if((seatNumber % 6) == 2 || (seatNumber % 6) == 5|| seatNumber == 5,2 ) {
typeOfSeat = 'M';
}
else {
typeOfSeat = 'A';
}
return typeOfSeat;
}
This does not do what you think it does:
seatNumber == 5,2
If you want to check against both values, you need separate conditionals
else if((seatNumber % 6) == 2 || (seatNumber % 6) == 5|| seatNumber == 5 || seatNumber == 2 ) {

How to pack three unsigned integers into an unsigned short in C

I have an assignment from college, in which I have to use C to pack three unsigned integers representing a date (the year must be between 1970 and 2097) and compress it into an unsigned short, then unpack it again and show it in command line.
Can someone help me please?
Below I leave the code I have so far (declared variables outside functions and function signatures cannot be changed)
Edit: I have a second problem, which is the getchar function not return anything, setting the three date fields to 0...
#include <stdio.h>
typedef unsigned short pkdate_t;
typedef struct date3 {
unsigned year;
unsigned month;
unsigned day;
} date3_t;
int ror (int val, unsigned n) {
return (val >> n)|(n << (32 - n));
}
int pack_date (pkdate_t * dst, date3_t * src) {
if ((*src).year < 1097 || (*src).year > 2097 || (*src).month < 1 || (*src).month > 12 || (*src).day < 1 ||
((*src).month == 2 && (((*src).year / 4 == 0 && (*src).day > 29) || ((*src).year / 4 != 0 && (*src).day > 28))) ||
(((*src).month == 2 || (*src).month == 4 || (*src).month == 6 || (*src).month == 9 || (*src).month == 11) && (*src).day == 31)) return -1;
//(*dst) = (*src).year * 10 + (*src).month + (*src).day; "wrong code"
return 0;
}
int unpack_date (date3_t * dst, pkdate_t date) {
(*dst).year = date % 10000;
date = date / 10000;
(*dst).month = date % 100;
date = date / 100;
(*dst).day = date % 100;
if ((*dst).year < 1097 || (*dst).year > 2097 || (*dst).month < 1 || (*dst).month > 12 || (*dst).day < 1 ||
((*dst).month == 2 && (((*dst).year / 4 == 0 && (*dst).day > 29) || ((*dst).year / 4 != 0 && (*dst).day > 28))) ||
(((*dst).month == 2 || (*dst).month == 4 || (*dst).month == 6 || (*dst).month == 9 || (*dst).month == 11) && (*dst).day == 31)) return -1;
else return 0;
}
int main () {
int k = ror(30, 2);
printf("%s\n", "exercicio 1:");
printf("%d turned into %d\n", 30, k);
pkdate_t date = 0;
date3_t newDate;
newDate.year = 2000;
newDate.month = 04;
newDate.day = 02;
printf("%s\n", "exercicio 2:");
//printf("%s\n", "insira uma data (yyyymmdd) e de seguida pressione enter:");
//int i = 1000;
//while (i > 0) {
//newDate.year += getchar() * i;
//i = i / 10;
//}
//i = 10;
//while (i > 0) {
//newDate.month += getchar() * i;
//i = i / 10;
//}
//i = 10;
//while (i > 0) {
//newDate.day += getchar() * i;
//i = i / 10;
//}
//"the commented part above does not get any values from command line, still figuring that part out :)"
pack_date(&date, &newDate);
printf("packed date: %hu\n", date);
unpack_date(&newDate, date);
printf("unpacked date: %u/%u/%u\n", newDate.year, newDate.month, newDate.day);
//newDate.year = 2000;
//newDate.month = 12;
//newDate.day = 14;
//pack_date(&date, &newDate);
//printf("%s\n", "exercicio 3:");
//printf("date is %hu\n", date);
// "ignore"
return 0;
}
In C, there aren't so much use cases that qualify for bitfields, but this one is a perfect fit IMHO since it saves you a lot of headaches from bit shifting:
struct date_struct
{
unsigned short year:7;
unsigned short month:4;
unsigned short day:5;
};
union date
{
struct date_struct bits;
short date;
}
First, you should think about how the date should be presented inside this unsigned short.
End even firster, you should be aware that the length of a(n unsigned) short is not defined exactly, only its minimum, which is 16 bits.
So let's try to pack such a date into 16 bits.
As already was commented as I write this answer, you can shrink the years into a range of y-1970 = 0..127, which makes you need 7 bits. The months need 4 bits and the days 5, in total 16 bits.
Now think about how you determine the single parts and how you shift them so that they fit.

Resources