I am solving an exercise in C and I got stuck. I don't know the logic of the code to get to my solution. For example we enter 2 numbers from input let the numbers be 123451289 and 12 and I want to see how many times number 2 is showing at number 1 (if this is confusing let me know). For the numbers earlier the program outputs 2. I tried solving it here is my code:
#include <stdio.h>
int main() {
int num1, num2, counter = 0;
scanf("%d%d", num1, num2);
if (num1 < num2) {
int temp = num1;
num1 = num2;
num2 = temp;
}
int copy1 = num1;
int copy2 = num2;
while (copy2 > 0) {
counter++; // GETTING THE LENGHT OF THE SECOND NUMBER
copy2 /= 10;
// lastdigits = copy1 % counter //HERE I WANT TO GET THE LAST DIGITS OF THE FIRST NUMBER
// But it does not work
}
}
My question is how can I get the last digits of the first number according to the second one for example if the second number have 3 digits I want to get the last 3 digits of the first number. For the other part I think I can figure it out.
I must solve this problem WITHOUT USING ARRAYS.
The problem: find all the needles (e.g. 12) in a haystack (e.g. 123451289).
This can be done simply without arrays using a modulus of the needle. For 12, this is 100. That is, 12 is two digits wide. Using the modulus, we can
isolate the rightmost N digits of the haystack and compare them against the needle.
We "scan" haystack repeatedly by dividing by 10 until we reach zero.
Here is the code:
#include <stdio.h>
int
main(void)
{
int need, hay, counter = 0;
scanf(" %d %d", &hay, &need);
// ensure that the numbers are _not_ reversed
if (hay < need) {
int temp = need;
need = hay;
hay = temp;
}
// get modulus for needle (similar to number of digits)
int mod = 1;
for (int copy = need; copy != 0; copy /= 10)
mod *= 10;
// search haystack for occurences of needle
// examine the rightmost "mod" digits of haystack and check for match
// reduce haystack digit by digit
for (int copy = hay; copy != 0; copy /= 10) {
if ((copy % mod) == need)
++counter;
}
printf("%d appears in %d exactly %d times\n",need,hay,counter);
return 0;
}
UPDATE:
I'm afraid this does not work for 10 0. –
chqrlie
A one line fix for to the modulus calculation for the 10/0 case. But, I've had to add a special case for the 0/0 input.
Also, I've added a fix for negative numbers and allowed multiple lines of input:
#include <stdio.h>
int
main(void)
{
int need, hay, counter;
while (scanf(" %d %d", &hay, &need) == 2) {
counter = 0;
// we can scan for -12 in -1237812
if (hay < 0)
hay = -hay;
if (need < 0)
need = -need;
// ensure that the numbers are _not_ reversed
if (hay < need) {
int temp = need;
need = hay;
hay = temp;
}
// get modulus for needle (similar to number of digits)
int mod = need ? 1 : 10;
for (int copy = need; copy != 0; copy /= 10)
mod *= 10;
// search haystack for occurences of needle
// examine the rightmost "mod" digits of haystack and check for match
// reduce haystack digit by digit
for (int copy = hay; copy != 0; copy /= 10) {
if ((copy % mod) == need)
++counter;
}
// special case for 0/0 [yecch]
if ((hay == 0) && (need == 0))
counter = 1;
printf("%d appears in %d exactly %d times\n", need, hay, counter);
}
return 0;
}
Here is the program output:
12 appears in 123451289 exactly 2 times
0 appears in 10 exactly 1 times
0 appears in 0 exactly 1 times
UPDATE #2:
Good fixes, including tests for negative numbers... but I'm afraid large numbers still pose a problem, such as 2000000000 2000000000 and -2147483648 8 –
chqrlie
Since OP has already posted an answer, this is bit like beating a dead horse, but I'll take one last attempt.
I've changed from calculating a modulus of needle into calculating the number of digits in needle. This is similar to the approach of some of the other answers.
Then, the comparison is now done digit by digit from the right.
I've also switched to unsigned and allow for the number to be __int128 if desired/supported with a compile option.
I've added functions to decode and print numbers so it works even without libc support for 128 bit numbers.
I may be ignoring [yet] another edge case, but this is an academic problem (e.g. we can't use arrays) and my solution is to just use larger types for the numbers. If we could use arrays, we'd keep things as strings and this would be similar to using strstr.
Anyway, here's the code:
#include <stdio.h>
#ifndef NUM
#define NUM long long
#endif
typedef unsigned NUM num_t;
FILE *xfin;
int
numget(num_t *ret)
{
int chr;
num_t acc = 0;
int found = 0;
while (1) {
chr = fgetc(xfin);
if (chr == EOF)
break;
if ((chr == '\n') || (chr == ' ')) {
if (found)
break;
}
if ((chr >= '0') && (chr <= '9')) {
found = 1;
acc *= 10;
chr -= '0';
acc += chr;
}
}
*ret = acc;
return found;
}
#define STRMAX 16
#define STRLEN 100
const char *
numprt(num_t val)
{
static char strbuf[STRMAX][STRLEN];
static int stridx = 0;
int dig;
char *buf;
buf = strbuf[stridx++];
stridx %= STRMAX;
char *rhs = buf;
do {
if (val == 0) {
*rhs++ = '0';
break;
}
for (; val != 0; val /= 10, ++rhs) {
dig = val % 10;
*rhs = dig + '0';
}
} while (0);
*rhs = 0;
if (rhs > buf)
--rhs;
for (char *lhs = buf; lhs < rhs; ++lhs, --rhs) {
char tmp = *lhs;
*lhs = *rhs;
*rhs = tmp;
}
return buf;
}
int
main(int argc,char **argv)
{
num_t need, hay, counter;
--argc;
++argv;
if (argc > 0)
xfin = fopen(*argv,"r");
else
xfin = stdin;
while (1) {
if (! numget(&hay))
break;
if (! numget(&need))
break;
counter = 0;
// we can scan for -12 in -1237812
if (hay < 0)
hay = -hay;
if (need < 0)
need = -need;
// ensure that the numbers are _not_ reversed
if (hay < need) {
num_t temp = need;
need = hay;
hay = temp;
}
// get number of digits in needle (zero has one digit)
int ndig = 0;
for (num_t copy = need; copy != 0; copy /= 10)
ndig += 1;
if (ndig == 0)
ndig = 1;
// search haystack for occurences of needle
// starting from the right compare digit-by-digit
// "shift" haystack right on each iteration
num_t hay2 = hay;
for (; hay2 != 0; hay2 /= 10) {
num_t hcopy = hay2;
// do the rightmost ndig digits match in both numbers?
int idig = ndig;
int match = 0;
for (num_t need2 = need; idig != 0;
--idig, need2 /= 10, hcopy /= 10) {
// get single current digits from each number
int hdig = hcopy % 10;
int ndig = need2 % 10;
// do they match
match = (hdig == ndig);
if (! match)
break;
}
counter += match;
}
// special case for 0/0 et. al. [yecch]
if (hay == need)
counter = 1;
printf("%s appears in %s exactly %s times\n",
numprt(need), numprt(hay), numprt(counter));
}
return 0;
}
Here's the program output:
12 appears in 123451289 exactly 2 times
123 appears in 123451289 exactly 1 times
1234 appears in 123451289 exactly 1 times
1 appears in 123451289 exactly 2 times
0 appears in 10 exactly 1 times
0 appears in 0 exactly 1 times
1000000000 appears in 1000000000 exactly 1 times
2000000000 appears in 2000000000 exactly 1 times
This looks along the lines of what you're attempting.
You can use the pow() function from math.h to raise 10 to the power of how many digits you need for your modulus operation.
Compile with -lm or make your own function to calculate 10^num_digits
#include <stdio.h>
#include <math.h>
int main() {
int x = 123456789;
double num_digits = 3.0;
int last_digits = x % (int)pow(10.0, num_digits);
printf("x = %d\nLast %d Digits of x = %d\n", x, (int)num_digits, last_digits);
return 0;
}
Outputs:
x = 123456789
Last 3 Digits of x = 789
I think you are trying to ask :- if number1 = 1234567 and number2 = 673, then, length of number2 or number2 has 3 digits, so, you now want the last 3 digits in number1, i.e, '456', if I'm not wrong.
If that is the case, then, what you did to find the number of digits in num2 is correct, i.e,
while (copy2>0) {
counter++; // GETTING THE LENGHT OF THE SECOND NUMBER
copy2/=10;
}
you can do the same for number1 and find out its number of digits, then you can compare whether the number of digits in number2 is less than that in number1. Ex, 3 is less than number of digits in number1, so you can proceed further. Let's say number of digits in number1 is 7 and you want the last 3 digits, so you can do iterate over the digits in number1 till count of digits in number2 and pop out each last digit and store them in an array.
The code:
#include <stdio.h>
int main()
{
int num1,num2;
int count1 = 0, count2 = 0;
scanf("%d",&num1);
scanf("%d",&num2);
if(num1<num2){
int temp = num1;
num1 = num2;
num2 = temp;
}
int copy1 = num1;
int copy2 = num2;
while (copy1>0)
{
count1++;
copy1/=10;
}
while (copy2>0)
{
count2++;
copy2/=10;
}
// printf("num1 has %d digits and num2 has %d digits\n", count1, count2);
if (count1 >= count2)
{
int arr[count2];
int x = count2;
int p = num1;
int i = 0;
while (x > 0)
{
arr[i++] = p%10;
x --;
p/=10;
}
for (int j = 0; j < i; j++)
{
printf("%d ", arr[j]);
}
}
return 0;
}
output : 8 7 6
let's say, num1 = 12345678, num2 = 158, then arr = {8,7,6}.
You must determine the number of digits N of num2 and test if num1 ends with num2 modulo 10N.
Note these tricky issues:
you should not sort num1 and num2: If num2 is greater than num1, the count is obviously 0.
num2 has at least 1 digit even if it is 0.
if num1 and num2 are both 0, the count is 1.
if num2 is greater then INT_MAX / 10, the computation for mod would overflow, but there can only be one match, if num1 == num2.
it is unclear whether the count for 1111 11 should be 2 or 3. We will consider all matches, including overlapping ones.
to handle larger numbers, we shall use unsigned long long instead of int type.
Here is a modified version:
#include <limits.h>
#include <stdio.h>
int main() {
int counter = 0;
unsigned long long num1, num2;
if (scanf("%llu%llu", &num1, &num2) != 2) {
printf("invalid input\n");
return 1;
}
if (num1 == num2) {
/* special case for "0 0" */
counter = 1;
} else
if (num1 > num2 && num2 <= ULLONG_MAX / 10) {
unsigned long long copy1 = num1;
unsigned long long mod = 10;
while (mod < num2) {
mod *= 10;
}
while (copy1 > 0) {
if (copy1 % mod == num2)
counter++;
copy1 /= 10;
}
}
printf("count=%d\n", counter);
return 0;
}
Note that leading zeroes are not supported in either number: 101 01 should produce a count of 1 but after conversion by scanf(), the numbers are 101 and 1 leading to a count of 2. It is non trivial to handle leading zeroes as well as numbers larger than ULLONG_MAX without arrays.
This was the answer that i was looking for but thank you all for helping :)
#include <stdio.h>
#include <math.h>
int main(){
int num1,counter1,counter2,num2,temp,digit,copy1,copy2;
scanf("%d%d",&num1,&num2);
if(num1<num2){
temp = num1;
num1 = num2;
num2 = temp;
}
copy1 = num1;
copy2 = num2;
counter1 = counter2 = 0;
while (copy2>0) {
counter1++;
copy2/=10;
}
counter1 = pow(10,counter1);
if(num1> 1 && num2>1)
while (copy1>0) {
digit = copy1%counter1;
if(digit==num2){
counter2++;
}
copy1/=10;
} else{
if(num2<1){
while (copy1>0) {
digit = copy1%10;
if(digit==copy2){
counter2++;
}
copy1/=10;
}
}
}
printf("%d",counter2);
}
Task is to "Write a program to sum all the integers between 1 and 1000, that are divisible by 13, 15 or 17, but not by 30". Here is my code:
#include <stdio.h>
int main()
{
int number = 1;
int sum = 0;
while(number <= 1000) {
++number;
if(((number % 13 ==0) || (number % 15 ==0) || (number % 17 ==0)) && (number % 30 != 0)){
sum = sum + number;
}
}
printf("Sum equals to %d.\n", sum);
return (0);
}
Output in my case is "Sum equals to 77796."
While on one of the posts it has "sum = 76795".
I don't understand why is that, tried changing code in different ways, but couldn't get to that answer.
For an idea of the problem, start by looking at the difference in results. You get 77796, while you expect 76795. The difference between these is 1001, which is a very big hint.
The line ++number; adds one to number, and you have this line before the code that does the check. By doing this you remove 1 from your search domain, and add the value 1001 to it.
To fix this, you can move the increment below the main body of the loop, as it was in the original code:
#include <stdio.h>
int main()
{
int number = 1;
int sum = 0;
while (number <= 1000) {
if(((number % 13 == 0) || (number % 15 == 0) || (number % 17 == 0)) && (number % 30 != 0)){
sum = sum + number;
}
++number;
}
printf("Sum equals to %d.\n", sum);
return (0);
}
This could be better written using a for loop, which exist for this purpose:
#include <stdio.h>
int main()
{
int sum = 0;
for(int number = 1; number <= 1000; ++number) {
if(((number % 13 == 0) || (number % 15 == 0) || (number % 17 == 0)) && (number % 30 != 0)){
sum = sum + number;
}
}
printf("Sum equals to %d.\n", sum);
return (0);
}
Both of these output the desired result:
Sum equals to 76795.
I am new to programming. I am currently taking online lectures quite rigorously and completed a task using Luhn's Algorithm. It is just one script that runs straight through, but for my future-self I want to learn to code more efficiently as projects get bigger.
That is where my problem comes in. I cannot seem to understand how to define or call functions correctly and unable to revise my script into something more "efficient".
(Everything is already submitted and my script completes the task perfectly, according to the bot, so I am not trying to half-arse my work here just to be clear.)
This is the completed script with only the main function that runs straight through and took me about 12-15 hours to get it working without error from the beginning. Everything is written in C
#include <stdio.h>
#include <cs50.h>
#include <math.h>
int main(void)
{
// this grabs the number and verifies the correct amount of digits
int count;
long number = 0;
do
{
number = get_long("Number: ");
count = (number == 0) ? 1 : (log10(number) + 1);
if (count < 13 || count == 14 || count > 16)
{
printf("INVALID\n"); // This is to satisfy the uni. bot command check. Need a EOF for numbers with the wrong amount of digits.
return (0);
}
}
while (count < 13 || count == 14 || count > 16);
//printf("Digits: %i\n", count); // test print for debugging
//This finds the first two digits of input number
long int two = number;
while (two >= 100)
{
two = two / 10;
}
//printf("First two numbers: %li\n", two); // test print for debugging
// verifies card using mod10 (Luhn's)
long sum = 0;
long bigdigit = 0;
//printf("\nLUHN Number: %li\n\n", number); // test print for debugging
if (count == 13 || count == 15)
{
count += 1;
}
for (int i = count; i > 0; i--)
{
if (i % 2 == 0)
{
sum += (number % 10);
}
else
{
bigdigit = (2 * (number % 10));
sum += (bigdigit / 10 + bigdigit % 10);
}
number = (number / 10);
//printf("\nI : %i\n", i); // test print for debugging
//printf("Sum: %li\n", sum); // test print for debugging
//printf("Number: %li\n", number); // test print for debugging
}
if (sum % 10 == 0)
{
printf("VALID\n");
}
else
{
printf("INVALID\n");
return (0);
}
// checks what type of card
if (two == 34 || two == 37)
{
printf("AMEX\n");
return (0);
}
else if (two >= 51 && two <= 55)
{
printf("MASTERCARD\n");
return (0);
}
else if (two >= 40 && two <= 49)
{
printf("VISA\n");
return (0);
}
else
{
printf("INVALID\n");
return (0);
}
}
I was trying to split it into 3 functions of main to call.
long input_number();
bool luhn_check();
void company_check();
I am stuck with the second function and not sure if the third should be a void or not.
"Revised" Script v2
#include <stdio.h>
#include <cs50.h>
#include <math.h>
long input_number(long CCN);
int counter(long CCN, int count);
bool luhn_check(long CCN, int count);
long firsttwo(long CCN, long two);
void card_type(long two);
int main()
{
long CCN = 0;
int count = 0;
long two = 0;
CCN = input_number(CCN);
count = counter(CCN, count);
//printf("CCN: %li\n", CCN); //debugging purposes
//printf("Digits: %i\n", count); //debugging purposes
luhn_check(CCN, count);
two = firsttwo(CCN, two);
//printf("First Two: %li\n", two); //debugging purposes
card_type(two);
}
// this grabs the number and verifies the correct amount of digits
long input_number(long CCN)
{
int count = 0;
do
{
CCN = get_long("Number: ");
count = (CCN == 0) ? 1 : (log10(CCN) + 1);
if (count < 13 || count == 14 || count > 16)
{
//printf("INVALID\n"); // This is to satisfy the uni. bot command check. Need a EOF
//return (0);
}
}
while (count < 13 || count == 14 || count > 16);
return (CCN);
}
int counter(long CCN, int count)
{
do
{
count = (CCN == 0) ? 1 : (log10(CCN) + 1);
}
while (count < 13 || count == 14 || count > 16);
return (count);
}
// verifies card using mod10 (Luhn's)
bool luhn_check(long CCN, int count)
{
long sum = 0;
long bigdigit = 0;
//printf("\nLUHN Number: %ld\n\n", CCN); // test print for debugging
if (count == 13 || count == 15)
{
count += 1;
}
for (int i = count; i > 0; i--)
{
if (i % 2 == 0)
{
sum += (CCN % 10);
}
else
{
bigdigit = (2 * (CCN % 10));
sum += (bigdigit / 10 + bigdigit % 10);
}
CCN = (CCN / 10);
//printf("\nI : %i\n", i); // test print for debugging
//printf("Sum: %li\n", sum); // test print for debugging
//printf("Number: %li\n", CCN); // test print for debugging
}
if (sum % 10 == 0)
{
printf("VALID\n");
return (true);
}
else
{
printf("INVALID\n");
return (false);
}
}
// grabs the first two numbers
long firsttwo(long CCN, long two)
{
two = CCN;
//printf("TWO CCN: %li\n", two); // debugging purposes
while (two >= 100)
{
two = two / 10;
}
return (two);
}
// finds card type and ends
void card_type(long two)
{
if (two == 34 || two == 37)
{
printf("AMEX\n");
//return (0);
}
else if (two >= 51 && two <= 55)
{
printf("MASTERCARD\n");
//return (0);
}
else if (two >= 40 && two <= 49)
{
printf("VISA\n");
//return (0);
}
else
{
printf("INVALID\n");
//return (0);
}
}
I have completed the second version of the script with your suggestions, bar the str of input, I will try to tackle that method in the next version as I have not handled that type yet.
Besides running the program with a string rather than b, is there anything I could have done more efficiently?
Let me start with a few notes on your function input_number:
long input_number()
{
// this grabs the number and verifies the correct amount of digits
int count;
[ .... ]
while (count < 13 || count == 14 || count > 16);
// Once this while loop starts, it will never terminate!
// if count starts at 10 (which is less than 13), the body says "do nothing".
// so count will continue to be unchanged, and the while-loop will continue to run.
return (0); // Code after a return statement will never be reached
// So your printf-statement below will NEVER happen.
// It also seems unlikely you want to return Zero.
// You probably want to return count, or some other value.
printf("Digits: %i\n", count); // test print for debugging
}
Why is my code wrong?? I don't know why... This problem is to get a card number from the user and tell whether it is a valid card number or an invalid card number. It could either be an American Express card, MasterCard, or a Visa. American Express card has 15 digits and must either start with 34 or 36, while MasterCard has 16 digits and can start with 51, 52, 53, 54, 55. The Visa card must either have 13 or 16 digits, and must start with a 4. This problem also uses the Luhn's algorithm wherein to check if a card number is valid every other number starting from the tens place multiplied by two, then if added the digits no their product but their digits, so if you multiply 8 by 2 its 16 so you must add 1 + 6 and the other numbers. Then once you got the sum you must add them to the ones you didn't multiply by 2, then lastly if their sum is divisible by 10 then it is valid. I really don't know where I went wrong I've been looking at my code for almost 3 hours. Also noob programmer here..
#include<stdio.h>
int main(void)
{
//declare and initialize card number
long long number = 0;
//ask user for their credit card number
do
{
printf("Number: ");
scanf("%lli", &number);
}
while (number < 0);
//declare and initialize a counter for the number of the digits
int counter = 0;
long long temp = number;
//loop to count the number of digits
while (temp > 0)
{
temp /= 10;
counter++;
}
//statement for invalid digits
if (counter != 13 && counter != 15 && counter != 16)
{
printf("Invalid number of digits\n");
}
//array to store the digits individually
int digits[counter];
// loop to store the digits in the array
for (int i = 0; i < counter; i++)
{
digits[i] = number % 10;
number /= 10;
}
//loop to multiply every other digit by 2
for (int j = 1; j < counter; j += 2)
{
digits[j] *= 2;
}
// loop to separate then add digits that are greater than 10
for (int x = 1; x < counter; x += 2)
{
if (digits[x] > 10)
{
int s = digits[x] % 10;
digits[x] /= 10;
digits[x] = (digits[x] % 10) + s;
}
}
int sum = 0;
//loop to get the sum of all numbers
for (int y = 0; y < counter; y++)
{
sum += digits[y];
}
sum %= 10;
switch (sum)
{
case '0':
if (counter == 15 && (digits[14] == 3 && (digits[13] == 4 || digits[13] == 7)))
{
printf("American Express\n");
}
else if (counter == 16 && digits[15] == 5)
{
printf("Master Card\n");
}
else if (counter == 13 && digits [12] == 4)
{
printf("Visa\n");
}
else if (counter == 16 && digits[15] == 4)
{
printf("Visa\n");
}
break;
default:
printf("Invalid\n");
break;
}
}
There are three errors, and I'm ashamed that it took myself so long to spot especially the second one.
if (digits[x] > 10) is a kind of off-by-one error. Rather than greater than 10, the Description of the Luhn algorithm says: If the result of this doubling operation is greater than 9 …, so this has to be if (digits[x] > 9).
case '0': must rather be case 0:, since sum is an integer, not a character representation.
if (counter == 15 && (digits[14] == 3 && (digits[13] == 4 || digits[13] == 7))) fails because the digits have been modified by the algorithm in-place, so the 7 has become a 5. We could write if (counter == 15 && (digits[14] == 3 && (digits[13] == 4 || digits[13] == 7*2-9))) instead; same for else if (counter == 16 && digits[15] == 5).
I just enrolled in the online CS50 course and doing the pset1 about detecting valid credit card number. However, my algorithm does not work well as I expected. I used debugging tool to see step by step result, as long as variable i run from 1 to 9 it works perfectly, all values are added to the sum correctly. But when it comes to i = 10 and so on, the numNotSquared got assigned -8 and numSquared got assigned -16 and it keeps like that until the end of the number. Please help me with that, thank you.
// Headers and libraries
#include <stdio.h>
#include <cs50.h>
#include <math.h>
int main(void)
{
// Prompt user for card number
long cardNumber = get_long("Enter card number: ");
// Get the length of input
int length = floor(log10(cardNumber)) + 1;
// Range validation
if (length < 13 || length > 16)
{
printf("INVALID\n");
}
int numSquared = 0;
int numNotSquared = 0;
int sum = 0;
// Algorithm to detect valid card
// Based on Luhn's algorithm (https://lab.cs50.io/cs50/labs/2020/x/credit/)
for (int i = 1; i <= length; i++)
{
// If digit is on odd position then mutiply by two
if (i % 2 != 0)
{
{
numSquared = ((int)(cardNumber / pow(10, length - i)) % 10) * 2;
}
// If the total is >= 10, then sum the products' digit
if (numSquared >= 10)
{
sum += ((numSquared % 10) + 1);
}
else
{
sum += numSquared;
}
}
// If digit is on even position then add to the sum
else
{
numNotSquared = (int)(cardNumber / pow(10, length - i)) % 10;
sum += numNotSquared;
}
}
// Find remainder of (total / 10)
if (sum % 10 == 0)
{
if (floor(cardNumber / pow(10, length - 1)) == 4)
{
printf("VISA\n");
}
else
{
int firstTwoDigits = floor(cardNumber / pow(10, length - 2));
if (firstTwoDigits == 34 || firstTwoDigits == 37)
{
printf("AMEX\n");
}
else if (firstTwoDigits == 51 || firstTwoDigits == 52 || firstTwoDigits == 53 || firstTwoDigits == 54 || firstTwoDigits == 55)
{
printf("MASTERCARD\n");
}
}
}
else
{
printf("INVALID\n");
}
}