How to exit stdin when EOF is reached in C programming - c

I'm having troubles with my program. The aim of it is to read an input of numbers from the user, and when they stop inputting numbers (ctrl-d) it collects the inputted numbers and prints out 'Odd numbers were: blah blah'
and 'Even numbers were: blah blah'.
I'm having trouble with how to exit the program at EOF and when it feels like I have overcome that problem, another problem occurs which is my program doesn't print the numbers from the array. It only prints 'Odd numbers were:' and 'Even numbers were:'.
Any help is appreciated.
Thanks
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
int main(void) {
int n, i, array[1000];
i=0;
while (i = getchar() !=EOF) {
scanf("%d", &array[i]);
i++;
}
printf("Odd numbers were:");
i=0 ;
while(i = getchar() != EOF) {
if(array[i]%2!=0) {
printf(" %d", array[i]);
i++;
}
}
printf("\nEven numbers were:");
i=0 ;
while(i = getchar() !=EOF) {
if (array[i]%2==0) {
printf(" %d", array[i]);
i++;
}
}
printf("\n");
return 0;
}

Performing Single-Digit Conversion to int
You may be making things a bit harder on yourself than it needs to be. While you can use while (scanf ("%d", &array[i]) == 1) to read whitespace separated integers and avoid having to perform a manual conversion, if your intent is to read single-digits, then using getchar() is fine. (for that matter, you can read any multi-digit integer with getchar(), it is simply up to you to provide a conversion from the ASCII characters to final numeric value)
The manual conversion for single-digit characters is straight forward? When you read digits as characters, you are not reading the integer value represented by the digit, you are reading the ASCII value for the character that represents each digit. See ASCII Table and Description. In order to convert a single ASCII character digit to it's integer value, you must subtract the ASCII value of '0'. (note: the single-quotes are significant)
For example if you read a digit with int c = getchar();, then you need to subtract '0' to obtain the single-digit integer value, e.g. int n = c - '0';
When filling an array, you must ALWAYS protect against writing beyond the bounds of your array. If you declare int array[1000] = {0}; (which has available zero-based array indexes of 0-999), then you must validate that you never write beyond index 999 or Undefined Behavior results. To protect your array bounds, simply keep track of the number of indexes filled and test it is always below the number of array elements available, e.g.
while (n < MAX && (c = getchar()) != EOF) /* always protect array bounds */
if ('0' <= c && c <= '9') /* only handle digits */
array[n++] = c - '0'; /* convert ASCII to int */
Next, while you are free to test n % 2 (using the modulo operator), there is no need (little endian). Since any odd number will have its ones-bit set to 1, all you need is a simple bitwise comparison, e.g (7 in binary is 0111).
if (array[i] & 1) /* if ones-bit is 1, odd */
printf (" %d", array[i]);
Of course, for even numbers, the ones-bit will be 0 (e.g. 8 in binary is 1000), so the corresponding test can be:
if ((array[i] & 1) == 0) /* if ones-bit is 0, even */
printf (" %d", array[i]);
Putting all of the pieces together, you can store all single digits read in array and then segregate the even and odd numbers for printing in a very simple manner (note: neither stdlib.h or math.h are required),
#include <stdio.h>
#define MAX 1000 /* define a constant rather than use 'magic' numbers in code */
int main (void)
{
int array[MAX] = {0},
c, i, n = 0;
while (n < MAX && (c = getchar()) != EOF) /* always protect array bounds */
if ('0' <= c && c <= '9') /* only handle digits */
array[n++] = c - '0'; /* convert ASCII to int */
printf ("\narray : "); /* output array contents */
for (i = 0; i < n; i++)
printf (" %d", array[i]);
printf ("\narray - odd : ");
for (i = 0; i < n; i++)
if (array[i] & 1) /* if ones-bit is 1, odd */
printf (" %d", array[i]);
printf ("\narray - even : ");
for (i = 0; i < n; i++)
if ((array[i] & 1) == 0) /* if ones-bit is 0, even */
printf (" %d", array[i]);
putchar ('\n'); /* tidy up w/newline */
return 0;
}
Example Compilation with Warnings Enabled
$ gcc -Wall -Wextra -pedantic-std=gnu11 -Ofast -o bin/arrayevenodd arrayevenodd.c
Example Use/Output
$ echo "01234567890123456789" | ./bin/arrayevenodd
array : 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
array - odd : 1 3 5 7 9 1 3 5 7 9
array - even : 0 2 4 6 8 0 2 4 6 8
Look things over and let me know if you have further questions.
Performing Manual Multi-Digit Conversion to int
If you are needing to convert multi-digit integers from characters, the easy way is to use a function that provides the conversion for you (e.g. the scanf family of functions or by using line oriented with fgets or getline and parsing and converting the strings of digits with strtok and then strtol, or parsing with sscanf, etc.)
However, performing a manual conversion of individual characters read by getchar() into a multi-digit integers is straight forward. You simply check for a valid character than can begin an integer (including the prefixes of +/-) and sum each digit providing a proper offset for the place of the digit by increasingly multiplying the sum by 10 before adding (or actually subtracting if building a the sum as a negative sum for coding efficiency purposes) each digit until you reach the next non-digit and then you add the final sum to your array and advance the array index.
While building the sum, it is up to you to check for integer Overflow before adding the final sum to your array. (you can handle the overflow condition however you like, the example below just throws the error and exits)
The manual conversion probably adds about 20 lines of code, e.g.
#include <stdio.h>
#include <stdint.h> /* exact length types */
#include <limits.h> /* INT_X constants */
#define MAX 1000 /* define constant rather than use 'magic' number in code */
int main (void)
{
int array[MAX] = {0},
c, i, start = 0, sign = 1, n = 0;
int64_t sum = 0;
while (n < MAX && (c = getchar()) != EOF) { /* always protect array bounds */
if (!start) { /* flag to start building int */
start = 1; /* flag - working on int */
if (c == '+') /* handle leading '+' sign */
continue;
else if (c == '-') /* handle leading '-' sign */
sign = -1;
else if ('0' <= c && c <= '9') /* handle digits */
sum = sum * 10 - (c - '0'); /* note: sum always computed */
else /* as negative value */
start = 0; /* reset - char not handled */
}
else if ('0' <= c && c <= '9') { /* handle digits */
sum = sum * 10 - (c - '0'); /* convert ASCII to int */
if (sum < INT_MIN || (sign != -1 && -sum > INT_MAX))
goto err; /* check for overflow, handle error */
}
else { /* non-digit ends conversion */
if (sum) /* if sum has value, add to array */
array[n++] = sign != -1 ? -sum : sum;
sign = 1; /* reset values for next conversion */
start = 0;
sum = 0;
}
}
if (sum) /* add last element to array on EOF */
array[n++] = sign != -1 ? -sum : sum;
printf ("\narray : "); /* output array contents */
for (i = 0; i < n; i++)
printf (" %d", array[i]);
printf ("\narray - odd : ");
for (i = 0; i < n; i++)
if (array[i] & 1) /* if ones-bit is 1, odd */
printf (" %d", array[i]);
printf ("\narray - even : ");
for (i = 0; i < n; i++)
if ((array[i] & 1) == 0) /* if ones-bit is 0, even */
printf (" %d", array[i]);
putchar ('\n'); /* tidy up w/newline */
return 0;
err:
fprintf (stderr, "error: overflow detected - array[%d]\n", n);
return 1;
}
Example Use/Output
$ echo "1,2,3,5,76,435" | ./bin/arrayevenodd2
array : 1 2 3 5 76 435
array - odd : 1 3 5 435
array - even : 2 76
Example with '+/-' Prefixes
$ echo "1,2,-3,+5,-76,435" | ./bin/arrayevenodd2
array : 1 2 -3 5 -76 435
array - odd : 1 -3 5 435
array - even : 2 -76
Look over the new example and let me know if you have any more questions.

Change the input loop to:
n = 0;
while ( 1 == scanf("%d", &array[n]) )
++n;
What you actually want to do is keep reading numbers until the read attempt fails; this loop condition expresses that logic. Forget about EOF. (It would also be a good idea to add logic to stop when n reaches 1000, to avoid a buffer overflow).
In the output loops, you do not want to do any input, so it is not a good idea to call getchar(). Instead, use a "normal" loop, for (i = 0; i < n; ++i).

Related

checking if a string contains numbers

I want to check a passcode if it contain at least 2 numbers.
I tried it with a double for loop like this:
for(int i = 0; i <= count; i++)
{
for(int k = 0; k < 10; k++)
{
if(passcode[i] == k)
{
printf("yee\n");
break;
}
}
}
but it doesn't work
I thought for each 'round', k would be a number from 0 to 9, and if it would be equal to a number the user gave, it would (in this case) print something
(passcode is an input from the user and count is the amount of signs given in)
int sum = 0;
for(int i = 0; i <= count; i++)
{
if (passcode[i] >= '0' && passcode[i] <= '9')
{
sum++
}
}
if (sum >=2)
printf("At least two digits");
As mentioned in some comments, you can also use isdigit(), if you have access to this function.
One other important point (also in the comments): characters and their number meaning might be different: '2' is different from 2: '2' is a character, there are 256 ASCII characters. If you want to verify this with a number, you are generally dealing with the ASCII code of that character (which is 50 for the character '2').
the digits are just ascii values you need single comparision like.
int len = LENGHT_OF_STRING;
char * s = "the string";
for(int i = 0; i < len; i++){
if(s[i] >= '0' && s[i] <= '9'){
prinf("Found digit.");
}
}
your comparision of k belongs to [0, 10) is not a valid implementaion.
This is doing comparision of ascii value of i'th char to the above range.
You have another option -- let strpbrk() do the work for you. strpbrk() (in string.h) locates the first occurrence within a string of any of the characters specified in the second accept string. So in the case of digits, your accept string is simply "0123456789". The function returns a pointer to the first occurrence found, so you simply loop twice adding 1 to the returned pointer address before the second iteration, considering any NULL return a failure to find two digits in the string.
A short working example is:
#include <stdio.h>
#include <string.h>
#define DIGITS "0123456789"
#define NDIGITS 2
int main (int argc, char **argv) {
int ndigits = NDIGITS;
char *p = argv[1];
if (argc < 2 ) { /* validate 1 argument given for password */
fprintf (stderr, "error: insufficient input,\n"
"usage: %s password\n", argv[0]);
return 1;
}
while (ndigits--) { /* loop NDIGITS times */
if (!(p = strpbrk (p, DIGITS))) { /* get ptr to digit (or NULL) */
fputs ("error: password lacks 2 digits.\n", stderr);
return 1;
}
p += 1; /* increment pointer by 1 for next search */
}
puts ("password contains at least 2 digits");
}
Example Use/Output
$ ./bin/passwd2digits some2digitpass1
password contains at least 2 digits
or
$ ./bin/passwd2digits some2digitpass
error: password lacks 2 digits.
Let strpbrk() worry about how to find the digits -- all you need to do it use it. man 3 strpbrk

Repetition code in C isn't working for large numbers

I'm writing a code in C to find the digits that repeat in a given number, and the one that I wrote works fine for small numbers, but the output gets messed up if I input a large value, N < 1000.
Here is my code; please help me out!
For the input:
1839138012980192380192381090981839
I get this output:
0 2 3 5 7 8
#include <stdio.h>
int main()
{
int digit, digits[10], flag = 0, i;
long long num;
scanf("%lld", &num);
while (num)
{
digit = num % 10;
if (digits[digit])
flag = 1;
digits[digit]++;
num /= 10;
}
if (flag)
{
for (i = 0; i < 10; i++)
{
if (digits[i] > 1)
printf("%d ", i);
}
printf("\n");
}
else
printf("The are no repeated digits.\n");
return 0;
}
The long long type can only represent a limited range of numbers. In your C implementation, 1839138012980192380192381090981839 is too big for long long, and scanf("%lld", &num) does not work.
Instead, read each character of input using c = getchar();, where c is declared as an int. If, after getchar, c is EOF, stop looping and print the results. If c is not EOF, then check whether it is a digit using if (isdigit((unsigned char) c)). The isdigit function is defined in <ctype.h>, so include that header.
If the character is a digit, then convert it from a character to the number it represents using c - '0'. You can use int d = c - '0'; to store the number in d. Then increment the count for the digit d.
If the character is not a digit, you can decide what to do:
There will likely be a new-line character, '\n', at the end of the line the user entered. You may want to ignore it. When you see the new-line, you could end the loop and print the results, you could continue reading to see if there are any other digits or characters before EOF is seen and report a problem to the user if there are, or you could ignore it and continue looping.
There could be spaces in the input. You might want to ignore them, or you might want to report a problem to the user.
If there are other characters, you might want to report a problem to the user.
Here's another approach, which you could use with a string of some maximum length (defined by the constant MAX_LEN).
A string made up of a bunch of char will use one byte per character, so you can define MAX_LEN up to how many bytes you have in system memory, generally, although in practice you probably would use a much smaller and more reasonable number.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LEN 12345
int main()
{
int digit, digits_checker[10] = {0}, flag = 0, i;
char* num;
/* set aside space for the string and its terminator */
num = malloc(MAX_LEN + 1);
/* read num from input */
scanf("%s", num);
/* get the string length */
size_t num_length = strlen(num);
/* walk over every character in num */
for (size_t position = 0; position < num_length; position++)
{
/*
We assume that the value of num[position] is an
ASCII character, from '0' to '9'. (If you can't make
that assumption, check the input and quit with an
error, if a non-digit character is found.)
If the input is valid, the digits 0-9 in the ASCII
table start at 48 ('0') and end at 57 ('9'). Subtracting
48, therefore, gives you the integer value at each digit
in num.
*/
digit = num[position] - 48;
/*
Increment a counter for each digit
*/
digits_checker[digit]++;
}
/* num is no longer needed, so we free its memory */
free(num);
/* check each digit */
for (i = 0; i < 10; i++)
{
if (digits_checker[i] > 1) {
printf("%d ", i);
flag = 1;
}
}
if (!flag) {
printf("The are no repeated digits.\n");
}
else {
printf("\n");
}
return 0;
}
The suggestion to check input is a good one. You can't necessarily assume that what someone enters will be entirely made up of digit characters.
But hopefully this demonstrates how to set aside space for a string, and how to read through it, one character at a time.

Converting 3 digit decimal number to binary (C)

I need to convert 3 digit decimal number to binary using C.
My code:
#include <stdio.h>
#define TWO 2
int main() {
int dec_num; // demical number
int i = 0; // loop cunter
printf("type in 3 digits number to convert to binary\n");
scanf("%d", &dec_num);
while (++i <= 12) {
if (dec_num % TWO != 0) {
printf("1") ;
} else if (dec_num % TWO == 0) {
printf("0");
} else if (dec_num <= 0) {
break;
}
dec_num / TWO;
}
return 0;
}
The problem is that the number doesn't get divided by 2 at the end of the while loop how can I fix it?
You did not store the value of dec_num after the division.
dec_num / TWO; //<--------------------
Your while loop condition was also wrong.
while(++i <= 12) //<-------------------
You should perform the division operation until the number is greater than 0
According to the rules of binary to decimal, you should print 1s and 0s in reverse order. But in your code, you have changed the order. In order to fix that We could store the result in an array and then we could print the result in reverse order.
Here is your modified code,
#include <stdio.h>
#define TWO 2
int main()
{
int dec_num; // demical number
int i=0; // loop cunter
printf("type in 3 digits number to convert to binary\n");
int flag = scanf("%d",&dec_num); //<-----check the user input
if(flag!=1)
{
printf("Input is not recognized as an integer");
return 0;
}
int size=0;
int array[120] = {0}; //<-------to store the result
while(dec_num > 0){ //<------- while the number is greater than 0
if(dec_num % TWO !=0){
array[i] = 1;
}
else if(dec_num % TWO ==0){
array[i] = 0;
}
size = ++i; //<------- store the size of result
dec_num = dec_num / TWO; //<------- divide and modify the original number
}
for(i=size-1;i>=0;i--) //<------- print in reverse order
printf("%d",array[i]);
return 0;
}
My solution will assume that the input is a positive number and that maximal decimal 3 digit number can be presented by 10 bits (decimal 999 is binary 1111100111). I will also use the fact that the bit-wise operators are defined by the C standard and should take place. These operations on most of the architectures are very efficient and much faster than / or %.
#include <stdio.h>
#define MAX_BIN_DIGITS 10
#define ERR_INVALID_INPUT_VALUE 1
int main(void)
{
int dec_num; // demical input number
int i = MAX_BIN_DIGITS;
int bin_bit;
// storing the result at zero terminated string
char bin_res[MAX_BIN_DIGITS+1] = {0};
printf("Type in 3 digits number to convert to binary:\n");
if (1 != scanf("%d",&dec_num))
{
printf("Error: Invalid input value!");
return ERR_INVALID_INPUT_VALUE;
}
// Checking for 'i' here just to be safe in case of larger input than expected - 4 digits or more
while(i-- && dec_num)
{
bin_bit = dec_num & 1; // get the LSB
dec_num >>= 1; // remove the LSB from 'dec_num'
bin_res[i] = '0' + bin_bit; // store the LSB at the end as a char
}
// Print the array starting from the most significant bit which is '1'
// NOTE: Need to take care of special case when the input is '0', then 'i'
// will be equal to 'MAX_BIN_DIGITS-1'.
printf("%s\n", (i != MAX_BIN_DIGITS-1) ? &(bin_res[i+1]) ? "0");
return 0;
}
There are multiple problems in your code:
You do not test the return value of scanf(): you get undefined behavior if the user fails to input characters that can be converted to an integer.
You do not test if the number indeed has at most 3 digits.
You iterate up to 12 times, but 10 should suffice since 210 = 1024 which is greater than any 3 digit number
As a matter of fact, it should not even be necessary to limit the number of iterations, since you stop when the number drops to 0.
The tests are inconsistent: num % TWO is either 0 or 1, the second test is redundant and the third test is never executed, so the loop fails to detect proper termination condition.
dec_num / TWO; does not update dev_num, so your loop just keeps printing the least significant bit (and the test while (++i <= 12) is indeed necessary for the loop to stop).
if corrected, this loop would print the bits from the least significant to the most significant, which is probably not the expected behavior.
#define TWO 2 is not strictly speaking a mistake, but does not improve code readability or safety. Local coding rules might bar you from using non trivial numeric constants in the code: such a rule seems counter productive in this particular case.
It is considered good style to always end output lines with a newline.
beware of typos: demical number is cute and loop cunter is intriguing.
Here is a corrected version of your code, using your algorithm, to illustrate the unexpected output (last significant bit to most significant bit):
#include <stdio.h>
int main() {
int dec_num; // decimal number
printf("type in a 3 digit number to convert to binary\n");
if (scanf("%d", &dec_num) != 1) {
printf("invalid input\n");
return 1;
}
if (dec_num < 0 || dec_num > 999) {
printf("invalid value: must have at most 3 digits\n");
return 1;
}
for (;;) {
if (dec_num % 2 != 0) {
printf("1");
} else {
printf("0");
}
dec_num = dec_num / 2;
if (dec_num == 0)
break;
}
printf("\n");
return 0;
}
Here is a recursive version that outputs the bits in the proper order:
#include <stdio.h>
void output_binary(int num) {
if (num > 1)
output_binary(num / 2);
printf("%d", num % 2);
}
int main() {
int dec_num; // decimal number
printf("type in a 3 digit number to convert to binary\n");
if (scanf("%d", &dec_num) != 1) {
printf("invalid input\n");
return 1;
}
if (dec_num < 0 || dec_num > 999) {
printf("invalid value: must have at most 3 digits\n");
return 1;
}
output_binary(dec_num);
printf("\n");
return 0;
}
While you already have a valid answer correcting the failure to update dec_num following division and valid recursive methods provided by others, it is unclear whether you intend to allow entry of negative 3-digit values as well as positive values. An implementation that determines the size of the type and then shifts by one over each of the bits can provide a simple solution that will handle both positive and negative values.
For example the conversion part of the code shifting by 1 for each bit (indexed 31 -> 0) could be as simple as:
int main (void) {
int decnum = 0; /* user input number */
unsigned remain = 0; /* remainder after shift */
size_t nbits = sizeof decnum * CHAR_BIT; /* number of bits for type */
/* read decnum here */
printf ("decimal: %d\nbinary : ", decnum); /* output value */
while (nbits--) { /* write bits 31->0 while 1 bits remain */
if ((remain = decnum >> nbits)) /* shift saving shifted value */
putchar ((remain & 1) ? '1' : '0'); /* bit 0/1 output '0'/'1' */
}
putchar ('\n'); /* tidy up with newline */
}
(note: a simple ternary operator is used to determine whether to output '1' or '0')
The bigger part of your problem is the your failure to check the return of scanf. This is an open invitation for Undefined Behavior. Regardless of what function you use for user-input, you must validate that input succeeded before proceeding further. Otherwise you will invoke undefined behavior when you attempt to access an indeterminate value.
When using scanf in order to require valid input, you must handle three cases each time (1) did the user cancel input by pressing Ctrl+d generating a manual EOF? (Ctrl+z on windows), (2) did a matching or input failure occur? and (3) the good input case. Then, as is your case, you must further validate the input was in the proper range of values (a 3 digit number in your case). Additionally, to require valid input, you must handle any character that remains unread in the input buffer (as is the case for a matching failure, or if the user slipped and typed additional characters after the integer value.
Now it is completely fine to simply validate the input and return on an invalid input regardless of what caused the failure, but to require valid input it is up to you to handle all three cases, check that the input was within the valid range (and even then remove the trailing '\n' left by scanf preparing the input-buffer for whatever additional input may be taken later in your code.
Many times that will require more code than your actual calculation does, but it is critical. For instance in your case, if you wanted to require the user to enter valid input, you could replace the /* read decnum here */ with something similar to:
for (;;) { /* loop continually until valid input or canceled */
int rtn; /* variable to hold scanf return */
fputs ("enter 3 digit integer: ", stdout); /* prompt */
rtn = scanf ("%d", &decnum); /* read value, saving return */
if (rtn == EOF) { /* handle manual EOF cancelation */
fputs ("(user canceled input)\n", stderr);
return 1;
}
if (rtn == 0) { /* handle input failure */
empty_stdin(); /* always empty input buffer */
fputs (" error: invalid integer input.\n", stderr);
} /* validate 3 digit poisitive (or negative) number */
else if (decnum < -999 || (decnum > -100 && decnum < 100)
|| decnum > 999) {
empty_stdin();
fputs (" error: not a 3 digit number.\n", stderr);
}
else { /* handle good input case (break loop) */
empty_stdin();
break;
}
}
note: the helper function empty_stdin(). That can be implemented with getchar() to read and discard any characters causing problems, e.g.
void empty_stdin (void) /* helper function to empty stdin after bad input */
{ /* (as well as the trailing '\n' after good input) */
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
Putting it altogether, you could do something like the following:
#include <stdio.h>
#include <limits.h> /* for CHAR_BIT */
void empty_stdin (void) /* helper function to empty stdin after bad input */
{ /* (as well as the trailing '\n' after good input) */
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
int main (void) {
int decnum = 0; /* user input number */
unsigned remain = 0; /* remainder after shift */
size_t nbits = sizeof decnum * CHAR_BIT; /* number of bits for type */
for (;;) { /* loop continually until valid input or canceled */
int rtn; /* variable to hold scanf return */
fputs ("enter 3 digit integer: ", stdout); /* prompt */
rtn = scanf ("%d", &decnum); /* read value, saving return */
if (rtn == EOF) { /* handle manual EOF cancelation */
fputs ("(user canceled input)\n", stderr);
return 1;
}
if (rtn == 0) { /* handle input failure */
empty_stdin(); /* always empty input buffer */
fputs (" error: invalid integer input.\n", stderr);
} /* validate 3 digit poisitive (or negative) number */
else if (decnum < -999 || (decnum > -100 && decnum < 100)
|| decnum > 999) {
empty_stdin();
fputs (" error: not a 3 digit number.\n", stderr);
}
else { /* handle good input case (break loop) */
empty_stdin();
break;
}
}
printf ("decimal: %d\nbinary : ", decnum); /* output value */
while (nbits--) { /* write bits 31->0 while 1 bits remain */
if ((remain = decnum >> nbits)) /* shift saving shifted value */
putchar ((remain & 1) ? '1' : '0'); /* bit 0/1 output '0'/'1' */
}
putchar ('\n'); /* tidy up with newline */
}
Example Use/Output
$ ./bin/prnbin3digit
enter 3 digit integer: why?
error: invalid integer input.
enter 3 digit integer: -75
error: not a 3 digit number.
enter 3 digit integer: 1024
error: not a 3 digit number.
enter 3 digit integer: 127 and more junk
decimal: 127
binary : 1111111
Or the case with a negative value:
$ ./bin/prnbin3digit
enter 3 digit integer: -127
decimal: -127
binary : 11111111111111111111111110000001
Or the case where the user cancels input:
$ ./bin/prnbin3digit
enter 3 digit integer: (user canceled input)
While this ended up being longer than what a simple right-shift implementation of the conversion would have been, it is worth building good user-input habits now to avoid untold problems later. Look things over and let me know if you have further questions.

Array with stopping condition

The task is: a user types an char array and the programm stops when the last two values make a match with the first and second inserted values, then it prints only inserted int values.
For example, I type: 1,2,f,5,2,g,s,d,c,3,1,2
And get 1,2,5,3
This what I've got for now
int main()
{
setlocale(LC_ALL, "RUS");
char* A;
int i = 2, N;
//making an array
A = (char*)malloc(2 * sizeof(char));
printf("Enter an array \n");
//entering the first value
scanf_s("%c", &A[0]);
//second value
scanf_s("%c", &A[1]);
//next values
while (!(A[i - 1] == A[0] && A[i] == A[1]))
{
i++;
A = (char*)realloc(A, (i + 1)*sizeof(char));
scanf_s("%c", &A[i]);
}
system("pause");
return 0;
}
So now it makes a stop only if the first value makes a match and prints nothing. I am really confused
You can avoid dynamically allocating altogether and just focus on the logic of your task. While you can use scanf for reading character input, you are better served using a character-oriented input function such as getchar.
That said, it appears you want to read characters from stdin, only storing unique digits in your array, and then if the user enters digits that match your first two elements stored in your array, print the values stored in the array and exit. (If I have any of that wrong, please let me know in a comment)
First off, reading characters with scanf can be a bit finicky depending on the values separating the character. However since you are only concerned with storing digits, that makes things a bit easier.
To avoid dealing with malloc, just set some reasonable limit to size your array and check your stored elements against. A simple #define is all you need. For example:
#define MAXE 128
Will define a constant MAXE (for max elements), to test against as you fill your array. Just keep a count of the elements you add to the array, and if you reach your limit, exit.
You want to keep reading characters until one of two conditions are met: (1) you have added 128 values to your array with no exit condition tripped, or (2) the last two characters entered match the digits store in a[0] and a[1]. To set up your read you can do something like:
while (n < MAXE && scanf ("%c", &c) == 1) { ...
note: with getchar() you can avoid the non-portable _s function issue, among other pitfalls with the scanf family of functions. The changes are minimal to use getchar() instead of declaring c as type char, declare c as type int, and then change your assignment to c as follows:
while (n < MAXE && (c = getchar()) != EOF) {
After reading a character, (regardless of how), you want to test whether it is a digit, if not you are not storing it and it can't be part of your exit condition. So you can simply get the next char if it isn't a digit:
if (c < '0' || '9' < c)
continue;
(note: ctype.h provides the isdigit() function that can be used instead of the manual checks)
You want to store the first two digit regardless, and following those two, you want to store any new digits entered (not already stored), so you need to test the current digit against all digits previously stored to insure it is a unique digit. While you can code the logic several ways, in this case your test loop must test all values stored before making a decision to store the current digit. In this situation, and in situations where you need to break control within nested loop, the lowly goto statement is your best friend. Here if the digit is a duplicate, the goto simply skips to the dupes label passing over the assignment:
if (n > 1)
for (i = 0; i < n; i++)
if (c == a[i])
goto dupe;
a[n++] = c;
dupe:;
The last part of the puzzle is your exit condition. This is a bit tricky (but simply solved) because you know you will not store the preceding (or for Leffler, the penultimate) value in the array to test against (it being non-unique to the array). The trick is just to save the character from the last iteration to test against. (maybe in a variable called last). Now you can code your exit clause:
if (n > 2 && a[0] == last && a[1] == c)
break;
Putting it all together, you could do something like the following:
#include <stdio.h>
#define MAXE 128
int main (void) {
char a[MAXE] = "", c, last = 'a';
int i, n = 0;
printf ("Enter an array\n");
while (n < MAXE && scanf ("%c", &c) == 1) {
if (c < '0' || '9' < c)
continue;
if (n > 1)
for (i = 0; i < n; i++)
if (c == a[i])
goto dupe;
a[n++] = c;
dupe:;
if (n > 2 && a[0] == last && a[1] == c)
break;
last = c;
}
if (n < 3) {
fprintf (stderr, "error: minimum of 3 values required.\n");
return 1;
}
if (n == MAXE) {
fprintf (stderr, "warning: limit of values reached.\n");
return 1;
}
printf ("Values in array: ");
for (i = 0; i < n; i++)
putchar (a[i]);
putchar ('\n');
return 0;
}
How you handle the printing and error conditions are up to you. Those included above are just a thought on how you could cover your bases.
Note: gcc does not implement the optional _s functions, so you can make the change back to scanf_s if you need to.
Example Use/Output
$ ./bin/exitonmatch
Enter an array
1
2
f
5
2
g
s
d
c
3
1
2
Values in array: 1253
Look it over and let me know if you have any questions.
Accept Any Char as Termination/Store only Unique Digits
If the logic as you have explained, is to track the first two characters, regardless of whether they are digits and allow any character to serve as the termination check of first two entered sequence, the easiest way to handle that is to simply store the first two characters entered in a separate array (or two variables) and check each sequence of characters entered against them.
Adding this type check takes no more than a slight rearranging of the conditions in the original to allow a few checks on any character entered before considering only digits for storage in your array.
note: the cc (character count) variable was added to track the number of characters entered and the first array was added to hold the first two characters entered.
For example:
char a[MAXE] = "", first[TSTA] = "", last = 'a';
int c, cc = 0, i, n = 0;
printf ("Enter an array\n");
while (n < MAXE && (c = getchar()) != EOF) {
if (c < ' ') continue; /* skip non-print chars */
if (cc < 2) /* fill first[0] & [1] */
first[cc] = c; /* check term condition */
if (++cc > 2 && first[0] == last && first[1] == c)
break;
last = c; /* set last */
if (c < '0' || '9' < c) /* store only numbers */
continue;
if (n > 1) /* skip duplicates */
for (i = 0; i < n; i++)
if (c == a[i])
goto dupe;
a[n++] = c; /* digit and not a dupe - store it */
dupe:;
}
note: getchar is used above, but you can substitute scanf from the first example if you like.
Example Use/Output
Here there first two characters are a and b which serve as the termination sequence despite not being digits.
$ ./bin/exitonmatchgc
Enter an array
a
b
c
4
5
g
h
4
9
3
b
a
b
Values in array: 4593

Normalizing the frequency of letters in a given .txt file

The problem: Given a txt file, find the normalized frequencies of all the letters in the document.
For example if given letters.txt containing "aaabb"
Output would be:
Letter | Frequency
a 0.6
b 0.4
Non-letters or numbers should be ignored.
My solution so far:
Since they want to input a text file, my main() should receive command line arguments.
int main (int argc, char* argv[]){
I've made an EOF check using getchar()
while ((c=getchar()) != EOF){
and an if statement that checks if the char that getchar() is within the ASCII values for a->z or A->Z
if (argv[1][c] >= 'a' && argv[1][c] <= 'z' || argv[1][c] >= 'A' && argv[1]<= 'Z')
2 things here - I dont know if argv[1][c] is the right way to go about writing this but intuitively it made sense to me.
Once the check is satisfied, I want the corresponding letter to update a count specifically for its # position in the alphabet. Therefore needing a declared array that iterates for that letter each time it is found.
count[26];
Here is where I'm having troubles associating the letter a or A to position count[0] in the count array. I don't know how to code this part.
Why not create an int array that is of size 52 and have the first half of the array be for lower-case character counts and the upper half be for uppercase?
So in pseudocode:
#define ALPHA_COUNTS (52)
#define UPPER_OFFSET (26)
int counts[ALPHA_COUNTS] = {0};
for (char c : the_file_stream) {
if (c is an alphabet character) {
if (c is a lowercase character){
++counts[c - 'a'];
} else {
++counts[c - 'A' + UPPER_OFFSET];
}
}
}
Even easier would be to just create a table for all ASCII characters and just populate it for alphabet characters:
#define ASCII_COUNT (127)
int counts[ASCII_COUNT] = {0};
for (char c : the_file_stream) {
if (c is an alphabet character) {
++counts[c];
}
}
Then later on, you could just iterate through the set of [Aa-Zz] and check the counts of each of the characters.
Simplify the statistics gathering by counting the occurrence of all input.
Non-letters or numbers should be ignored in the result.
unsigned long long count[UCHAR_MAX + 1] = {0};
int ch;
while ((ch=getchar()) != EOF){
count[ch]++;
}
Now only sum the ones that are letters
unsigned long long sum = 0;
for (int i=0; i<=UCHAR_MAX; i++) {
if (isalpha(i)) {
sum += count[i];
// fold into lower case
if (isupper(i)) {
count[tolower(i)] += count[i];
count[i] = 0;
}
}
}
Print their frequency
for (int i=0; i<=UCHAR_MAX; i++) {
if (isalpha(i) && count[i] > 0) {
printf("%c %f\n", i, 1.0*count[i]/sum);
}
}
There are a number of different ways to approach the problem. You can make use the the functions provided in ctype.h (e.g. isalpha, tolower, toupper, etc.), or for the limited number of tests required, you can simply test the characters directly using arithmetic or basic bitwise operations. For example, you can test if a value is between 'a' and 'z' for lower-case, and for all characters the 6th-bit in 7-bit ASCII is the case-bit, so simply toggling the case-bit will change a character from upper-to-lower or vice versa.
The read then analyze approach chux outlined is an excellent approach to take. Any time you can separate input/output from processing data, you provide yourself a great deal of flexibility.
Using that logic, an example of using arithmetic and simple bitwise operations to analyze the frequency of alpha-characters ([A-Za-z]) which occur in a file can be written similar to the following. Note, the program will read from the filename provided as the first argument (or from stdin by default if no filename is given:
#include <stdio.h>
#include <limits.h>
int main (int argc, char **argv) {
unsigned long long count[UCHAR_MAX + 1] = {0}, sum = 0;
int c, i;
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
while ((c = fgetc(fp)) != EOF) count[c]++; /* fill count */
for (i = 0; i <= UCHAR_MAX; i++) {/* freq of only chars */
if ('A' <= i && i <= 'Z') { /* fold upper-case */
count[i ^ (1u << 5)] += count [i]; /* into lower */
count[i] = 0; /* zero index */
}
if ('a' <= i && i <= 'z') /* if lower-case */
sum += count[i]; /* add to sum */
}
printf ("\n total characters [A-Za-z]: %llu\n\n", sum);
for (i = 0; i <= UCHAR_MAX; i++)
if (count[i] > 0 && ('a' <= i && i <= 'z'))
printf (" %c%c : %.2f\n", i ^ (1u << 5), i, 1.0 * count[i]/sum);
putchar ('\n');
if (fp != stdin) fclose (fp); /* close if not stdin */
return 0;
}
Examples Use/Output
Using your example of 'aaabb' the program produces the following:
$ ./bin/char_freq < <(echo "aaabb")
total characters [A-Za-z]: 5
Aa : 0.60
Bb : 0.40
A slightly longer example shows the full character selection of only [A-Za-z]:
$ ./bin/char_freq < <(echo "*(a)123A_a/B+4b.")
total characters [A-Za-z]: 5
Aa : 0.60
Bb : 0.40
Look over this answer as well as all the others and let me know if you have additional questions.

Resources