I have a text file of combinations without repetition of 6 number ranging from 1 to 10, like this:
2 3 8 9 6 4
8 3 1 4 7 9
1 3 5 7 6 9
1 5 7 9 8 4
1 3 5 4 8 7
2 4 6 8 7 1
6 7 8 3 5 9
3 1 6 2 7 9
1 7 4 2 5 8
3 4 9 2 1 7
...
and I have a gold combination, let's say: 2, 1, 3, 9, 8, 5
I want to check how many times I have a combination in my text file that matches 5 numbers of the gold combination. This is my code attempt:
// Including C Standard Libraries
#include <stdint.h>
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main()
{
// Gold Combination
int n1 = 2;
int n2 = 1;
int n3 = 3;
int n4 = 9;
int n5 = 8;
int n6 = 5;
// Numbers of Matching Combinations
int match_comb = 0;
// Creating a file to see combinations content
char ch, file_name[25];
FILE *fp;
fp = fopen("combinations.txt", "r"); // Read Mode
if (fp == NULL)
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
int j = 0;
int mn = 0; // Number of matched numbers
int x[6] = {0,0,0,0,0,0};
char c;
while((c = fgetc(fp)) != EOF)
{
if(c == ' ' || c == '\n')
{
}
else
{
x[j] = c;
if (j == 5)
{
if(x[0]==n1 || x[0]==n2 || x[0]==n3 || x[0]==n5 || x[0]==n6){
mn += 1;
}if(x[1]==n1 || x[1]==n2 || x[1]==n3 || x[1]==n5 || x[1]==n6){
mn += 1;
}if(x[2]==n1 || x[2]==n2 || x[2]==n3 || x[2]==n5 || x[2]==n6){
mn += 1;
}if(x[3]==n1 || x[3]==n2 || x[3]==n3 || x[3]==n5 || x[3]==n6){
mn += 1;
}if(x[4]==n1 || x[4]==n2 || x[4]==n3 || x[4]==n5 || x[4]==n6){
mn += 1;
}if(x[5]==n1 || x[5]==n2 || x[5]==n3 || x[5]==n5 || x[5]==n6){
mn += 1;
}
if ( mn == 5)
{
match_comb += 1; // Adding One the the Match Combinantions counter
}
for (int i = 0; i < 6; ++i) // Resetting x array
{
x[i] = 0;
}
mn = 0; // Resetting
j = -1; // Resetting j
}
j += 1;
}
}
printf("Number of Matching Combinations:");
printf("%d", match_comb);
printf("\n");
fclose(fp);
return 0;
}
But, I think the code is not working, because it always says that there are 0 matched combinations .. Are there ways to simplify or make my code work?
also, this only works for the case of numbers with one digit, but in the case I have bigger range, let's say 1-20, I am not really sure how to gather the numbers from the text file .. I was thinking in a condition where there was a counter after every space, if the counter is one, take the character as a number of one digit, if the counter is two, gather the two characters and do something to tell the code to gather the two characters and use the resulted number, but I don't know how to do that ..
Edit:
int main()
{
// Gold Combination
int n1 = 20;
int n2 = 1;
int n3 = 35;
int n4 = 9;
int n5 = 18;
int n6 = 5;
// Numbers of Matching Combinations
int match_comb = 0;
// Creating a file to see combinations content
char ch, file_name[25];
FILE *fp;
fp = fopen("combinations.txt", "r"); // Read Mode
if (fp == NULL)
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
int j = 0;
int mn = 0; // Number of matched numbers
int x[6] = {0,0,0,0,0,0};
int c;
while((c = fgetc(fp)) != EOF)
{
//x[j] = fscanf(fp, "%d", &c);
fscanf(fp, "%d %d %d %d %d %d", &x[0], &x[1], &x[2], &x[3], &x[4], &x[5]);
printf("%d", x[0]);
printf(" ");
printf("%d", x[1]);
printf(" ");
printf("%d", x[2]);
printf(" ");
printf("%d", x[3]);
printf(" ");
printf("%d", x[4]);
printf(" ");
printf("%d", x[5]);
if(x[0]==n1 || x[0]==n2 || x[0]==n3 || x[0]==n5 || x[0]==n6){
mn += 1;
}if(x[1]==n1 || x[1]==n2 || x[1]==n3 || x[1]==n5 || x[1]==n6){
mn += 1;
}if(x[2]==n1 || x[2]==n2 || x[2]==n3 || x[2]==n5 || x[2]==n6){
mn += 1;
}if(x[3]==n1 || x[3]==n2 || x[3]==n3 || x[3]==n5 || x[3]==n6){
mn += 1;
}if(x[4]==n1 || x[4]==n2 || x[4]==n3 || x[4]==n5 || x[4]==n6){
mn += 1;
}if(x[5]==n1 || x[5]==n2 || x[5]==n3 || x[5]==n5 || x[5]==n6){
mn += 1;
}
if ( mn == 5)
{
match_comb += 1; // Adding One the the Match Combinantions counter
}
for (int i = 0; i < 6; ++i) // Resetting x array
{
x[i] = 0;
}
mn = 0; // Resetting
printf("\n");
}
printf("Number of Matching Combinations:");
printf("%d", match_comb);
printf("\n");
fclose(fp);
return 0;
}
The problem lies with:
x[j] = c;
This assigns a char to an integer. You need to convert c to an integer. For example by subtracting the character code of zero:
x[j] = c-'0';
You can use isdigit(c) to check whether c is really a digit.
Either with the help of the debugger or by using printf to show the exact values of the x[0], x[1], ... you get a clearer view of what was going wrong.
As for reading numbers of more than 1 digit, the best idea is to use a function such as fscanf(fp, "%d", &c) which automatically converts the read characters to a number. Note that if you use &c here, c needs to be an int, not a char.
If you want to work with fscanf, you need to remove the calls to fgetc (in your while-loop), because otherwise fgetc everytime removes a character. Removing a character is no problem when that's a space or a newline, but it is a problem for the first digit in the line. When fgetc can not be used anymore for checking end-of-file, use the return value of fscanf as explained in this post. For example:
while (true) // endless loop, but will end via a 'break'
{
// remove if(c == ' ' || c == '\n')
if (fscanf(fp, "%d", &c) != 1) // check whether fscanf found 1 input
break; // this jumps out of the while loop
.... // rest of your code
}
If you really want to use fgetc for reading the numbers, you need something like:
if (isdigit(c))
num = num * 10 + (c - '0');
and not yet putting num in the X-array until you encounter a non-digit. num needs to be reset to 0 thereafter.
As for the code you use for calculating the number of matches, it looks quite clever if you're fully new to programming. An improvement would be to also put the n values in an array and to use for-loops to check the number of matches.
Related
I tried this to parse data given in a csv file into ID, AGE, and GPA fields in a "data" file, but I don't think I'm doing this right (when I tried printing the data, its printing weird numbers). What am I doing wrong?
char data[1000];
FILE *x = fopen("database.csv","rt");
char NAME[300];
int ID[300],AGE[300],GPA[300];
int i,j;
i = 0;
while(!feof(x)) {
fgets(data,999,x);
for (j = 0; j < 300 && data[i] != ','; j++, i++) {
ID[j] = data[i];
i++;
}
for (j = 0; j < 300 && data[i] != ','; j++, i++) {
NAME[j] = data[i];
i++;
}
for (j = 0; j < 300 && ( data[i] != '\0' || data[i] != '\r' || data[i] != data[i] != '\n'); j++, i++) {
GPA[j] = data[i];
}
}
First of all: for what you're doing, you probably want to look carefully at the function strtok and the atoi macro. But given the code you posted, that's perhaps still a bit too advanced, so I'm taking a longer way here.
Supposing that the line is something like
172,924,1182
then you need to parse those numbers. The number 172 is actually represented by two or four bytes in memory, in a very different format, and the byte "0" is nothing like the number 0. What you'll read is the ASCII code, which is 48 in decimal, or 0x30 in hex.
If you take the ASCII value of a single digit and subtract 48, you will get a number, because fortunately the numbers are stored in digit order, so "0" is 48, "1" is 49 and so on.
But you still have the problem of converting the three digits 1 7 2 into 172.
So once you have 'data':
(I have added commented code to deal with a unquoted, unescaped text field inside the CSV, since in your question you mention an AGE field, but then you seem to want to use a NAME field. The case when the text field is quoted or escaped is another can of worms entirely)
size_t i = 0;
int number = 0;
int c;
int field = 0; // Fields start at 0 (ID).
// size_t x = 0;
// A for loop that never ends until we issue a "break"
for(;;) {
c = data[i++];
// What character did we just read?
if ((',' == c) || (0x0c == c) || (0x0a == c) || (0x00 == c)) {
// We have completed read of a number field. Which field was it?
switch(field) {
case 0: ID[j] = number; break;
case 1: AGE[j] = number; break;
// case 1: NAME[j][x] = 0; break; // we have already read in NAME, but we need the ASCIIZ string terminator.
case 2: GPA[j] = number; break;
}
// Are we at the end of line?
if ((0x0a == c) || (0x0c == c)) {
// Yes, break the cycle and read the next line
break;
}
// Read the next field. Reinitialize number.
field++;
number = 0;
// x = 0; // if we had another text field
continue;
}
// Each time we get a digit, the old value of number is shifted one order of magnitude, and c gets added. This is called Horner's algorithm:
// Number Read You get
// 0 "1" 0*10+1 = 1
// 1 "7" 1*10+7 = 17
// 17 "2" 17*10+2 = 172
// 172 "," Finished. Store 172 in the appropriate place.
if (c >= '0' && c <= '9') {
number = number * 10 + (c - '0');
}
/*
switch (field) {
case 1:
NAME[j][x++] = c;
break;
}
*/
}
I'm working on a program that checks the validity of credit card numbers for the CS50 class I'm taking (it's legal I swear haha) and I'm currently working on correctly getting the first two numbers of each CC# to check what company it is from. I've commented what each part does for clarity and also commented where my problem arises.
#include <stdio.h>
#include <stdlib.h>
#include <cs50.h>
#include <math.h>
#include <string.h>
int main(void)
{
long long ccn = get_long_long("Enter CCN: \n");
int count = 0;
long long ccn1 = ccn;
// finds the amount of digits entered and stores that in int count.
while (ccn1 != 0)
{
ccn1 /= 10;
+count;
}
printf("%i \n", count);
// ln 17- 19 should take int count, subtract two, put that # as the power of 10,
// then divide the CC# by that number to get the first two numbers of the CC#.
long long power = count - 2;
// here is where i get the error. its a long long so it
// should hold up to 19 digits and im only storing 14 max
// but it says that 10^14th is too large for type 'int'
long long divide = pow(10,power);
long long ft = ccn / divide;
printf("power: %i \n", power); //ln 20-22 prints the above ints for debug
printf("Divide: %lli \n", divide);
printf("First two: %lli \n", ft);
string CCC;
// ln 24-35 cross references the amount of digits in the CC#
// and the first two digits to find the comapany of the credit card
if ((count == 15) && (ft = 34|37))
{
CCC = "American Express";
}
else if ((count == 16) && (ft = 51|52|53|54|55))
{
CCC = "MasterCard";
}
else if ((count = 13|16) && (ft <=49 && ft >= 40))
{
CCC = "Visa";
}
printf("Company: %s\n", CCC);
}
The first issue is the +count in the loop. This should be ++count. Because of this, count stays at 0 and power = -2. You can avoid all that power stuff. You already have the loop, you can use it to get the first two digits:
int ft = 0;
while (ccn1 != 0)
{
// When you are down to 10 <= ccn1 < 100, store it
if (ccn1 < 100 && ccn1 > 9) ft = ccn1;
ccn1 /= 10;
++count;
}
Your second issue is how you do your comparisons.
if ((count == 15) && (ft = 34|37))
First, = is assignment, and == tests equality. Second, | is bitwise OR, || is logical OR. Third, you can't test multiple values like that. Correct way:
if ((count == 15) && (ft == 34 || ft == 37))
i have a code that prints out the number of peaks and their given magnitudes. the input is in the form of a single line that contains random integers separated by white space. a peak is only defined to be so when it is directly preceded and followed by a smaller value.
examples:
0 4 18 18 26 40 40 29 25 2 0 //has one peak of magnitude 40.
20 10 20 /*has no peaks, because both 20's are either not
preceded or followed by a smaller number.*/
the code fails to behave correctly when the input data, c, begins with a declining set of numbers.
for example, the input: 9 8 7 6 5 4 returns a peak of "9", when it shouldn't return any magnitude.
another situation where it's behaving incorrectly is when we have the following input: 10 10 10 5 5 5 12 12 12 -1. its returning a magnitude of "10", while again, it shouldn't return any magnitude because it doesn't fulfill the conditions of a peak .
the following is the code:
#include <stdio.h>
int main(void)
{
int a = 0;
int b = 0;
int c = 0;
int counter = 0;
scanf("%d", &c);
printf("Number Magnitude\n");
while (c >= 0){
if ((b > a) && (b > c)) { //to check if we have a peak
counter++;
printf("%4d%11d\n", counter, b);
a = b;
b = c;
scanf("%d", &c);
}
else if ((a < b) && (b == c)) {
b = c;
scanf("%d", &c);
}
else {
a = b;
b = c;
scanf("%d", &c);
}
}
}
i prefer to keep the level of coding as minimum as possible, as i haven't done more than loops and if statements at this stage.
The issue is being caused because you initialize your boundary values to the minimum possible value. Any possible peak value will test positive when compared to that boundary value.
A small change fixes it, both boundary values should be set to a value that tests negative when compared to any possible peak value:
int a = INT_MAX;
int b = INT_MAX;
You will however to detect new lines and reset your values if you want to be able to do multiple lines of input, but I believe this is an existing problem
In that case, you should try to ask the program to mimic what you would to by hand: you must considere 3 value, so you must read 3 values before testing for a peak. And you should always control the return value from scanf to be able to process and end of file or an incorrect input.
Your code could become:
#include <stdio.h>
int main(void)
{
int a = 0;
int b = 0;
int c = 0;
int counter = 0;
int cr;
cr = scanf("%d%d%d", &a,&b,&c);
if (cr != 3) {
printf("Incorrect input\n");
return 1;
}
printf("Number Magnitude\n");
while ((cr > 0) && (c >= 0)) {
if ((b > a) && (b > c)) { //to check if we have a peak
counter++;
printf("%4d%11d\n", counter, b);
a = b;
b = c;
}
else if ((a >= b) || (b != c)) {
a = b;
b = c;
} // nothing to do if a<b and b==c
cr = scanf("%d", &c); // read once outside of the loop
}
return 0;
}
BTW, above code allows multi-line input.
I'm a first time programmer trying to complete a simple command line program as part of the first assignment for an online course I am taking, but I seem to have hit a roadblock that I can't figure out with GDB or my own research.
After hours of rewrites, and hours of debugging, I finally got the code below to compile. The program is supposed to take a credit card number as an input, and then check whether it's valid per the specifications of the assignment. I used a test number from here: PayPal Test Credit Cards
The odd thing is, when I enter an AMEX card number, it correctly produces the text "AMEX", but when I try a Visa or a Master Card, it prints "INVALID".
In GDB I broke at the Verify function and it seems to incorrectly skip these two if/else if statements without proceeding to the Checksum function even though conditions appear to be met.
if (firstDigit == 4 && totalDigits == (13 | 16) && Checksum(cardNumber, totalDigits) == 0) // checks for a valid Visa.
...
else if (firstDigit == 5 && secondDigit == (1 | 2 | 3 | 4 | 5) && totalDigits == 16 && Checksum(cardNumber, totalDigits) == 0) // checks for a valid Mastercard.
...
The AMEX line of code that correctly executes is:
else if (firstDigit == 3 && secondDigit == (4 | 7) && totalDigits == 15 && Checksum(cardNumber, totalDigits) == 0) // checks for a valid American Express.
The arguments for all three lines seem to be formatted exactly the same. That is far as I could get in GDB though. I would print totalDigits, firstDigit, and secondDigit in GDB right before stepping through the above two non-executing lines and everything looked correct. So I'm stumped, why is the AMEX line executing, but not the others?
Thanks in advance everyone. This is the first program after hello.c that I've tried to write, so I am open to absolutely any criticism or suggestions if it looks like I'm doing something weird/wrong.
Full code:
checker.c
#include <stdio.h>
#include <stdlib.h>
int MAX = 16;
int* DigitSort(unsigned long long x, int* array);
int Verify(int* array);
int main (void)
{
int* output = malloc (sizeof(int) * (MAX + 2)); // creates a blank array for the individual digits of the card number.
unsigned long long userInput = 0;
do
{
printf("Please enter a credit card number:\n");
scanf("%lld", &userInput);
}
while (userInput <= 0); // checks to make sure the user entered a number.
switch(Verify(DigitSort(userInput, output))) // sorts the user's input into individual digits and verifies the card type and validity.
{
case 1 :
printf("VISA\n");
break;
case 2 :
printf("MASTERCARD\n");
break;
case 3 :
printf("AMEX\n");
break;
case 0 :
printf("INVALID\n");
break;
default :
printf("INVALID\n");
}
free(output);
return 0;
}
int Verify(int* array) // verifies whether or not a card number is valid. Must pass the function a sorted array of individual digits.
{
int* cardNumber = array;
int firstDigit = cardNumber[0];
int secondDigit = cardNumber[1];
int totalDigits = 0;
int Checksum(int* cardNumber, int totalDigits);
int i = 0;
while (firstDigit >= 1 && cardNumber[i] >= 0) // this step counts the number of digits in the array.
{
totalDigits = totalDigits + 1;
i++;
}
if (firstDigit == 4 && totalDigits == (13 | 16) && Checksum(cardNumber, totalDigits) == 0) // checks for a valid Visa.
{
return 1;
}
else if (firstDigit == 5 && secondDigit == (1 | 2 | 3 | 4 | 5) && totalDigits == 16 && Checksum(cardNumber, totalDigits) == 0) // checks for a valid Mastercard.
{
return 2;
}
else if (firstDigit == 3 && secondDigit == (4 | 7) && totalDigits == 15 && Checksum(cardNumber, totalDigits) == 0) // checks for a valid American Express.
{
return 3;
}
else // if the card number doesn't match any of the above conditions or fails the checksum, an 'I' for Invalid is returned.
{
return 0;
}
}
int* DigitSort(unsigned long long x, int* array) // takes a long long as input and sorts it into individual digits
{
int* arrayReversed = malloc (sizeof(int) * (MAX + 2)); // creates a new array to hold the reversed order of digits.
int i = 0;
arrayReversed[0] = 0;
if (i < (MAX - 1) && x >= 10)
{
do
{
arrayReversed[i] = x % 10;
x = x / 10;
i++;
}
while (i < (MAX -1) && x >= 10);
}
if (i < MAX && x >= 1 && x <= 9)
{
arrayReversed[i] = (int) x;
x = (x - x);
}
if (x == 0)
{
int j = 0;
do
{
array[j] = arrayReversed[i]; // sorts the digits from the reversed array and places them into the sorted array.
j++;
i--;
}
while (j < MAX && i >= 0);
array[j] = -1;
}
free(arrayReversed);
return array;
}
int Checksum(int* cardNumber, int totalDigits)
{
int sum1 = 0;
int sum2 = 0;
int i = (totalDigits - 2);
int j = (totalDigits - 1);
while (i >= 0)
{
sum1 = ((cardNumber[i] * 2)%10) + ((cardNumber[i] * 2)/10) + sum1;
i -= 2;
}
while (j >= 0)
{
sum2 = (cardNumber[j] + sum2);
j -= 2;
}
if (((sum1 + sum2) % 10) == 0)
{
return 0;
}
else
{
return 1;
}
}
Your first problem is here:
if (firstDigit == 4 && totalDigits == (13 | 16) && ...
You need to write:
if (firstDigit == 4 && (totalDigits == 13 || totalDigits == 16) && ...
Your first check is looking for 0x1D == 29 as the number of digits (because, as paisanco points out in a comment, the | operator is the bitwise OR operator), and no credit card needs 29 digits (yet, and not for a long time to come). Note the extra parentheses for clarity and accuracy. Don't mess around risking removing them — the code won't work properly again. And in general, be explicit if your condition has both && and || operators and use parentheses to group terms explicitly.
You have similar problems elsewhere. As it happens, (4 | 7) is the same value as 7, so the condition works when the second digit is 7 (but not when it is 4). But it doesn't mean what you intended it to mean.
Computer languages don't work the same as human languages. Get used to writing out the condition somewhat more verbosely. Some other languages provide shorthands for these conditions; C is not such a language.
I'm trying to solve the Adding Reversed Numbers problem (ADDREV) at the Sphere Online Judge but my submission keeps coming up wrong answer.
I've tried int, unsigned int, long, and unsigned long for my variables and they all work equally well on my computer with some test data (also below) but they all fail the SPOJ.
I'm hoping someone might be able to shed some insight into why my program would be failing on their system. I've also left a message on their forum but there doesn't seem to be a lot of traffic.
Here's my code:
#include <stdio.h>
#define FIRST 1
#define SECOND 2
int main()
{
int c, k, x, y, state, place, total, reverse = 0;
do
{
c = getchar();
if (c < 48 || c > 57)
{
continue;
}
else
{
k = k * 10;
k = k + (c - 48);
}
} while (c != '\n');
state = FIRST;
place = 1;
do
{
c = getchar();
if (c == ' ')
{
state = SECOND;
place = 1;
continue;
}
else if (c == '\n')
{
total = x + y;
place = 1;
while ((total / place) >= 10)
{
place = place * 10;
}
while (place > 0)
{
reverse = reverse + ((total % 10) * place);
total = total / 10;
place = place / 10;
}
printf("%d\n", reverse);
state = FIRST;
place = 1;
reverse = 0;
x = 0;
y = 0;
k--;
continue;
}
if (state == FIRST && (c >= 48 && c <= 57))
{
x = x + ( (c - 48) * place );
place = place * 10;
}
else if (state == SECOND && (c >= 48 && c <= 57))
{
y = y + ((c - 48) * place );
place = place * 10;
}
} while (k > 0);
return 0;
}
And... here's the test data I'm using:
12
24 1
4358 754
305 794
2762 2563
435 4320
0 0
123 456
20 20
10000 10000
999999 999999
321 583
9999999 999999
And here's the results my program gives on my computer:
34
1998
1
4236
867
0
579
4
2
8999991
805
89999901
Any help would be appreciated :)
At this point:
int c, k, x, y, state, place, total, reverse = 0;
you create a variable k but give it no value. Shortly after:
k = k * 10;
you use this variable. At that point, your program exhibits undefined behaviour - anything might happen.