Related
I want to write a program which reads a line of input from the user, in the following format: <Name>,<Age>,<City>
The Name can contain English letters, spaces and - only.
The Age must be an integer between 18 to 120.
The City must contain English letters and - only.
Each of them can be of size 49.
I want to store the information and print an informative error will be printed for bad input.
My code is the following:
char str[150];
char input[3][50] = { 0 };
int num = 0;
if (fgets(str, 150, stdin) != NULL) {
num = sscanf(str, "%[a-zA-Z -],%[0-9],%[a-zA-Z-]", input[0], input[1], input[2]);
}
if (num < 3) {
printf("ERROR\n");
}
The problem is that an error will not be printed for an input such as Name1$#,20,NY, Best,19,Rome123, or Best,100,Paris1$, where the city is in wrong format (with trailing characters). There is any way to solve it using sscanf?
You can use sscanf() and character classes for your purpose but there are small problems with your format string:
A-Z assumes ASCII encoding or at least an encoding where letters are contiguous.
a trailing - has a special meaning, put the dash in first position to match a dash explicitly.
there is no length prefix, so a name or city longer than 49 characters will overflow the destination array.
Rather than using fgets(), you should read the line mannually to detect overlong lines.
You can add an extra %c to check for extra characters at the end of the line. Storing the converted value is not required if you don't intend to use the field values, but you must convert the number to check if its value is in the requested range:
char str[150];
char name[50];
char city[50];
char agestr[4];
size_t i;
int c, age, pos, n;
for (i = 0; (c = getchar()) != EOF && c != '\n'; i++) {
if (i < sizeof(str) - 1)
str[i] = (char)c;
}
if (c == EOF && i == 0) {
printf("end of file\n");
return -1;
}
if (i >= sizeof(str)) {
printf("line too long\n");
return 0;
}
str[i] = '\0';
pos = 0;
/* validate the name */
if (sscanf(str + pos, "%49[-a-zA-Z ]%n", name, &n) != 1 || str[pos + n] != ',') {
printf("invalid name\n");
return 0;
}
pos += n + 1;
/* validate the age */
if (str[pos] == '0' || sscanf(str + pos, "%3[0-9]%n", agestr, &n) != 1 || str[pos + n] != ',') {
printf("invalid age\n");
return 0;
}
age = atoi(agestr);
if (age < 18 || age > 120) {
printf("age out of range: %d\n", age);
return 0;
}
pos += n + 1;
/* validate the city */
if (sscanf(str + pos, "%49[-a-zA-Z]%n", city, &n) != 1 || str[pos + n] != '\0') {
printf("invalid city\n");
return 0;
}
/* Input was validated... proceed */
Here's my code:
include <stdio.h>
int main()
{
char str[1000], ch;
int i, frequency = 0;
printf("Enter a string: ");
gets(str);
printf("Enter a character to find the frequency: ");
scanf("%c",&ch);
for(i = 0; str[i] != '\0'; ++i)
{
if(ch == str[i])
++frequency;
}
printf("Frequency of %c = %d", ch, frequency);
return 0;
I figured that the frequency of characters code I came up with is similar. How to implement the character which appears more / less often in standard input or text file?
Also, should I use StreamReader sr = new StreamReader("example.txt") for reading normal text files for this code?
EDIT: Have to use Switch /M for most often and /L for least often.
That's a good start...
include <stdio.h>
int main()
{
char str[1000], ch,lookup_Chars[256];
int i, frequency = 0;
char counter;
printf("Enter a string: ");
gets(str);
printf("Enter a character to find the frequency: ");
scanf("%c",&ch);
for(i = 0; str[i] != '\0'; ++i)
{
lookup_Chars[str[i]]++;
}
for(counter = 0; counter<sizeof(lookup_Chars); counter++)
{
printf("Frequency of %c = %d", counter, lookup_Chars[counter]);
}
return 0;
Never, never, never use gets. It is so insecure and so susceptible to buffer overrun, it has been removed from the C standard library. Use fgets instead, just be aware that fgets will read and include the trailing '\n' in the buffer it fills (just as all legitimate line oriented input functions do, such as POSIX getline). This prevents leaving a '\n' unread in the input buffer (e.g. stdin) following each user input.
You risk Undefined Behavior because you do not validate the contents of str in any way and then you fail to validate the return of scanf to insure a character was read. (the user could cancel input in either case by generating an EOF with Ctrl+d on *nix systems of with Ctrl+z on windoze).
Further, you must understand that scanf will leave characters in the input buffer (as will fgets if the line is longer than the amount of storage you have allocated). That is one of the most common pitfalls new C programmers fall victim to. (failing to validate a complete line of input was read and failing to handle characters that remain in the input buffer)
When taking user input with fgets (which is recommended), since it reads and includes the '\n' in the buffer it fills, you simply check the length of the buffer read with strlen and then make sure the last character is a '\n'.
scanf is full of pitfalls when used for user input. While it can be used, if used correctly with it's return validated and any remaining characters emptied from stdin before your next call to scanf, you have to approach it use that way. In your case ch is the last input for your file, but try taking input for ch before reading the string and see what happens...
Putting it altogether, and adding validations for both str and ch, and adding additional comments in-line below, you could do something similar to the following:
#include <stdio.h>
#include <string.h>
#define MAXS 1024 /* if you need a constant, define one */
int main (void) {
int frequency = 0;
char str[MAXS] = "",
*p = str, /* pointer to str */
ch;
printf ("Enter a string: ");
if (fgets (str, MAXS, stdin)) { /* validate input received */
size_t len = strlen (str); /* get length of str */
if (len && str[len - 1] != '\n') { /* validate all input read */
fprintf (stderr, "error: line exceeds %d chars.\n", MAXS-2);
return 1;
}
}
else { /* if fgets failed - user generated EOF to cancel */
fprintf (stderr, "error: user canceled input (EOF).\n");
return 1;
}
printf ("Enter a character to find the frequency: ");
if (scanf ("%c", &ch) != 1) { /* note: chars will remain in stdin */
fprintf (stderr, "error: user canceled input.\n");
return 1;
}
while (*p != '\n') /* just use a pointer to str */
if (*p++ == ch) /* compare to ch and increment to next char */
frequency++; /* increment frequency if they are equal */
printf ("\nFrequency of %c = %d\n", ch, frequency);
return 0;
}
(note: you could declare char ch[3] = ""; and use fgets to read fgets (ch, sizeof ch, stdin) and then simply compare if (*p++ == *ch) to prevent leaving the '\n' in stdin (but you would still need to validate that it was the final character read, and if not manually empty stdin))
Exammple Use/Output
$ ./bin/freqofc
Enter a string: a man a plan a canal panama
Enter a character to find the frequency: a
Frequency of a = 10
$ ./bin/freqofc
Enter a string: a man a plan a canal panama
Enter a character to find the frequency: p
Frequency of p = 2
$ ./bin/freqofc
Enter a string: a man a plan a canal panama
Enter a character to find the frequency: z
Frequency of z = 0
Look things over, think about the validations that were made, and let me know if you have any further questions.
Using a Frequency Array to Capture Count of all Chars
Using a frequency array allows you to capture the frequency of all characters (or the independent count of any element of a set). Essentially, you use an array initialized to zero with one element for each member of the set you want to count the frequency of each occurrence. Since there are 128 ASCII Characters, you can simply use an array of 128 elements, e.g. int frequency[128] = {0};.
If you look at the link provided, you see the ASCII value of each character corresponds to a value between 0-127, so when looping over each character in the input string, if you increment the array index that corresponds to the character, you end up with the total count for each character in its corresponding element. For example, if p is a pointer to the beginning of str, then you can loop over each character in the string capturing their frequency in the frequency[*p] element of the array:
while (*p != '\n') {
frequency[*p]++; /* increments element corresponding to char *p */
p++; /* note: cast to (int)*p intentional omitted */
}
Now that you have the frequency for every character stored in the frequency, you can simply loop over the elements you are concerned about to determine max/min, etc... Note: the normal printable characters begin with 'space' (ASCII 32, or hex 0x20) and end with '~' (ASCII 126 or hex 0x7e`). So just limit your check of values to the printable range, e.g.
/* loop over printable characters (see ASCII Chart), for max/min */
for (int i = ' '; i <= '~'; i++) {
/* require a frequency of at least 1 for min */
if (frequency[i] && frequency[i] < min) {
min = frequency[i]; /* save least frequent count */
minc = i; /* save least frequent char */
}
if (frequency[i] > max) { /* just find max */
max = frequency[i]; /* save same for max */
maxc = i;
}
}
(note: you can further micro-divide ranges for only lowercase, uppercase, digits, etc..)
Putting that altogether, you can do something similar to the following to report the number of occurrence if the wanted char, the max occurring char, the min occurring char (and then summarize by dumping the frequency of all chars):
#include <stdio.h>
#include <string.h>
#include <limits.h>
#define MAXS 1024 /* if you need a constant, define one */
#define NASCII 128 /* number of ASCII chars (includes non-printing) */
int main (void) {
int frequency[NASCII] = {0},
max = INT_MIN,
min = INT_MAX;
char str[MAXS] = "",
*p = str, /* pointer to str */
ch,
minc = 0,
maxc = 0;
printf ("Enter a string: ");
if (fgets (str, MAXS, stdin)) { /* validate input received */
size_t len = strlen (str); /* get length of str */
if (len && str[len - 1] != '\n') { /* validate all input read */
fprintf (stderr, "error: line exceeds %d chars.\n", MAXS-2);
return 1;
}
}
else { /* if fgets failed - user generated EOF to cancel */
fprintf (stderr, "error: user canceled input (EOF).\n");
return 1;
}
printf ("Enter a character to find the frequency: ");
if (scanf ("%c", &ch) != 1) { /* note: chars will remain in stdin */
fprintf (stderr, "error: user canceled input.\n");
return 1;
}
while (*p != '\n') /* just use a pointer to str */
frequency[(int)*p++]++; /* increment element representing ch */
/* loop over printable characters (see ASCII Chart), for max/min */
for (int i = ' '; i <= '~'; i++) {
/* require a frequency of at least 1 for min */
if (frequency[i] && frequency[i] < min) {
min = frequency[i]; /* save least frequent count */
minc = i; /* save least frequent char */
}
if (frequency[i] > max) { /* just find max */
max = frequency[i]; /* save same for max */
maxc = i;
}
}
/* ouput requested char freq, and max/min chars */
printf ("\nFrequency of %c = %d\n"
"least frequent occurrence: %c = %d\n"
" most frequent occurrence: %c = %d\n\n",
ch, frequency[(int)ch], minc, min, maxc, max);
/* output frequency of all printable chars */
printf ("frequency of all printable characters:\n");
for (int i = ' '; i < '~'; i++)
if (frequency[i])
printf (" '%c' : %d\n", i, frequency[i]);
return 0;
}
Exammple Use/Output
$ ./bin/freqofc2
Enter a string: a man a plan a canal panama
Enter a character to find the frequency: m
Frequency of m = 2
least frequent occurrence: c = 1
most frequent occurrence: a = 10
frequency of all printable characters:
' ' : 6
'a' : 10
'c' : 1
'l' : 2
'm' : 2
'n' : 4
'p' : 2
Adding /L or /M Switches for Least/Max Occurrences
To add command line switches, for a minimum number in a known order, you can simply use the allowable argument count and argument vector parameters to main(), e.g. int main (int argc, char **argv). Example:
int main (int argc, char **argv) {
...
/* validate "/L" or "/M" provided as an argument */
if (argc != 2 || (argv[1][1] != 'L' && argv[1][1] != 'M')) {
fprintf (stderr, "error: insufficient input, req'd /M or /L.\n");
return 1;
}
To test and output either the least or minimum, you simply test which character is present and act accordingly, e.g.
...
if (argv[1][1] == 'L') /* output requested lease or max */
printf ("requested least frequent occurrence: %c = %d\n\n",
minc, min);
else
printf ("requested most frequent occurrence: %c = %d\n\n",
maxc, max);
Putting that together an a complete example would be:
#include <stdio.h>
#include <string.h>
#include <limits.h>
#define MAXS 1024 /* if you need a constant, define one */
#define NASCII 128 /* number of ASCII chars (includes non-printing) */
int main (int argc, char **argv) {
int frequency[NASCII] = {0},
max = INT_MIN,
min = INT_MAX;
char str[MAXS] = "",
*p = str, /* pointer to str */
ch,
minc = 0,
maxc = 0;
/* validate "/L" or "/M" provided as an argument */
if (argc != 2 || (argv[1][1] != 'L' && argv[1][1] != 'M')) {
fprintf (stderr, "error: insufficient input, req'd /M or /L.\n");
return 1;
}
printf ("Enter a string: ");
if (fgets (str, MAXS, stdin)) { /* validate input received */
size_t len = strlen (str); /* get length of str */
if (len && str[len - 1] != '\n') { /* validate all input read */
fprintf (stderr, "error: line exceeds %d chars.\n", MAXS-2);
return 1;
}
}
else { /* if fgets failed - user generated EOF to cancel */
fprintf (stderr, "error: user canceled input (EOF).\n");
return 1;
}
printf ("Enter a character to find the frequency: ");
if (scanf ("%c", &ch) != 1) { /* note: chars will remain in stdin */
fprintf (stderr, "error: user canceled input.\n");
return 1;
}
while (*p != '\n') /* just use a pointer to str */
frequency[(int)*p++]++; /* increment element representing ch */
/* loop over printable characters (see ASCII Chart), for max/min */
for (int i = ' '; i <= '~'; i++) {
/* require a frequency of at least 1 for min */
if (frequency[i] && frequency[i] < min) {
min = frequency[i];
minc = i;
}
if (frequency[i] > max) { /* just find max */
max = frequency[i];
maxc = i;
}
}
/* ouput requested char freq, and max/min chars */
printf ("\nFrequency of %c = %d\n"
"least frequent occurrence: %c = %d\n"
" most frequent occurrence: %c = %d\n\n",
ch, frequency[(int)ch], minc, min, maxc, max);
if (argv[1][1] == 'L') /* output requested lease or max */
printf ("requested least frequent occurrence: %c = %d\n\n",
minc, min);
else
printf ("requested most frequent occurrence: %c = %d\n\n",
maxc, max);
/* output frequency of all printable chars */
printf ("frequency of all printable characters:\n");
for (int i = ' '; i < '~'; i++)
if (frequency[i])
printf (" '%c' : %d\n", i, frequency[i]);
return 0;
}
Let me know if you have any questions.
Can someone help me to solve my problem? I have a problem with %[^\n]. When I try to enter a false input the program loop the warning that I wrote, but if I use %s and I enter my string the next statement is not working properly.
#pragma warning (disable:4996)
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(){
char name[30];
char number[12];
int flag, flag1, flag2, flag3;
int i;
printf("Add New Contact\n");
do {
printf("input name [1..30 char]: ");
scanf("%[^\n]", name); fflush(stdin);
if ((name[0] >= 'A' && name[0] <= 'Z') || (name[0] >= 'a' && name[0] <= 'z')) {
flag = 1;
}
else {
flag = 0;
printf("First letter of name should be an alphabet (A-Z or a-z)\n");
}
if (strlen(name) > 30) {
flag1 = 0;
printf("Length of name should be between 1 and 30 characters\n");
}
else {
flag1 = 1;
}
} while (flag == 0 || flag1 == 0);
do {
printf("Input phone number[6..12 digits]: ");
scanf("%s", number); fflush(stdin);
for (i = 0; i < strlen(number); i++) {
if (number[i] >= '0' && number[i] <= '9') {
flag2 = 1;
}
else {
flag2 = 0;
}
}
if (flag2 == 0) {
printf("Phone numbers should only contain digits (0-9)\n");
}
if (strlen(number) >= 6 && strlen(number) <= 12) {
flag3 = 1;
}
else {
flag3 = 0;
printf("Length of phone numbers should be between 6 and 12 digits\n");
}
} while (flag2 == 0 || flag3 == 0);
printf("\n");
printf("New contact successfully added!\n");
printf("Press Enter to continue...");
getchar();
getchar();
return 0;
}
Oh by the way, the problem might simply be that the scanf call leaves the newline in the buffer, and if you loop and try again the first character seen will be the newline and scanf should not read any thing.
There are two things you should do: First check what scanf returns, it should return 1 if it read a string. Secondly you should tell scanf to discard any possible leading white-space by adding a space first in the format string: " %[^\n]".
Most scanf formats automatically skips leading white-space, but not when using the "%[" or "%c" formats.
Also, to not worry about writing out of bounds of the array, you should add a length modifier to make sure that scanf doesn't read more input than it can write: " %29[^\n]". If the length of the string is 29 after this, then you should probably read until you reach the end of the line, character by character.
Here is your program fixed:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
// In case you need this -- not needed for this case
void discard_input()
{
char c;
while( ( c = getchar() ) != '\n' && c != EOF );
}
void remove_trailing_newline(char * s)
{
char * ch = s + strlen( s ) - 1;
while( ch != s ) {
if ( *ch == '\n' ) {
*ch = 0;
break;
}
--ch;
}
return;
}
int main(){
char name[30];
char number[12];
int flag, flag1, flag2, flag3;
int i;
printf("Add New Contact\n");
do {
printf("\nInput name [1..30 char]: ");
fgets( name, 30, stdin );
remove_trailing_newline( name );
flag1 = flag = 1;
if ( !isalpha( name[ 0 ] ) ) {
flag = 0;
printf("First letter of name should be an alphabet (A-Z or a-z), found: %s\n", name );
}
// impossible
if (strlen(name) > 30) {
flag1 = 0;
printf("Length of name should be between 1 and 30 characters\n");
}
} while (flag == 0 || flag1 == 0);
do {
printf("\nInput phone number[6..12 digits]: ");
fgets( number, 12, stdin );
remove_trailing_newline( number );
flag2 = flag3 = 1;
int len_phone = strlen( number );
for (i = 0; i < strlen(number); i++) {
if ( !isdigit( number[ i ] ) ) {
flag2 = 0;
}
}
if (flag2 == 0) {
printf("Phone numbers should only contain digits (0-9), found:'%s'\n", number);
}
if ( len_phone < 6 || len_phone > 12) {
flag3 = 0;
printf("Length of phone numbers should be between 6 and 12 digits, found: %d\n", len_phone );
}
} while (flag2 == 0 || flag3 == 0);
printf("\n");
printf( "Name: '%s'\n", name );
printf( "Phone: '%s'\n", number );
printf("New contact successfully added!\n");
printf("Press Enter to continue...");
getchar();
return 0;
}
You can find the program here.
The fixings are more or less interesting, I enumerate they here:
At first, I thought that the problem was that the trailing new line was being left in the input buffer. fflush(stdin) is actually undefined behaviour in C, since the fflush() function is there for output streams. Anyway, I included the code in question 12.26b of the comp.lang.c FAQ, since I think it is interesing to have it as reference. Then, I decided to change scanf() with fgets(). This is due to the scanf() taking spaces as delimiters, so you wouldn't be able to write a complete name, i.e., name and surname. Remember that gets() is not an option, since it writes the input past the limit of the buffer. Actually, fgets() solves this by letting us define a limit of chars to read. The problem is that fgets() also includes the '\n' in the buffer, so, that's why I included the remove_trailing_newline() function. Tricky, isn't it?
You added a condition to check whether the name input had more than thirty chars. Actually, this is impossible to check in your program. First of all, fgets() will read 29 chars + the final char mark (0). Secondly, if you were actually allowing to input more than 30 chars, then the input would be written past the size of the buffer, which is undefined behaviour (crashes in most cases). You would have to use something more complex, like std::string in C++, and then check its length. Or maybe use a third party expandable string for C. Or roll out your own expandable string...
You can decide whether there is an alphabetic char or a digit by using isalpha(c) and isdigit(c) functions.
When you are going to use a value many times, such as strlen(name), then you should precompute it and store it in a local variable. Though a good compiler (its optimizer) will detect this situation and solve it for you, you never know which compiler is going to compile your code, and how advanced it is. Also, there is nothing wrong making things easier for the optimizer.
When you have a situation in which you set a flag for signaling an error condition, it is easier to set it to the "no error" value before checking anything, and solely in case of an error, set it to the "error" value. This will be easier to read, and therefore, to understand.
Hope this helps.
I have a code here that has a job to see if the user input is either string or integer from a range of 1-49. If I enter "asdas" it says invalid, and if I enter a integer from "1-49" it says valid. The problems I am having with this code is that if I enter "2 asda"
it will it count it has valid, and invalid at the same time, and if I enter "2 2" It will consider that valid as well. Just found out it also accepts "2d" as a valid input to.
for (i = 0; i < 6; i++)
{
printf("\nPlease enter the %d winning ticket numbers!: ", i+1);
if (scanf("%d", (&winningNumbers[i])) == 0 || (winningNumbers[i] <= 0) || (winningNumbers[i] >= 50))
{
inputFlush();
printf("\nInvalid Input. Please re-enter.\n") ;
i = i - 1;
}
}
for (i = 0; i < 6; i++)
{
printf("%d, ", winningNumbers[i]);
}
Read the entire line into a string (fgets, line 2 in the snippet). Read data from the string using sscanf: read the integer and one more character, after a space. Check whether sscanf returns something different than 1. If it does then you either have strings in the beginning (it returns 0 since it couldn't read an integer) or you have extra whitespace characters at the end (that is it also matched the %c format specifier). The space is needed to jump over whitespace until the end of the line (including the stored \n).
printf("\nPlease enter the %d winning ticket numbers!: ", i+1);
fgets(buffer, size, stdin);
if (sscanf(buffer, "%d %c", &winningNumbers[i], &c) != 1 || (winningNumbers[i] <= 0) || winningNumbers[i] >= 50))
{
// inputFlush(); not needed now that you read the entire line
printf("\nInvalid Input. Please re-enter.\n") ;
i = i - 1;
}
Look at this example.
#define MAX_LINE_SIZE 500
int main(int argc, char** argv)
{
char line[MAX_LINE_SIZE];
unsigned int num;
char *ptr;
while (fgets(line, MAX_LINE_SIZE, stdin) != NULL){
num = strtol(line, &ptr, 10);
if (line[0] != '\n' && (*ptr == '\n' || *ptr == '\0')) {
printf("Your num: %u\n", num); // check num if you need
} else {
printf("Error\n");
}
}
return 0;
}
The output:
12
Your num: 12
45
Your num: 45
34 2
Error
ads
Error
Here fgets function read data from stdin. strtol parse read string and assign an address of a char after parsed number to ptr pointer. Assuming that user has to input only one number (without any character after) we have to check whether *ptr is new line or end of line.
line[0] != '\n' prevents empty string.
Check the next character using peek, as detailed here. You can tell if it's good or not that way.
Another SO question that's pretty much the same.
The program I am writing to take a number and display that number as a calculator would display it (shown below) is compiling with no issues, but when I try to run it, I am able to input my number, but nothing happens. It seems like it is "hanging", since no further output is shown as I would have expected. Might anyone know what the problem is?
#include <stdio.h>
#define MAX_DIGITS 20
char segments[10][7] = /* seven segment array */
{{'1','1','1','1','1','1','0'}, /* zero */
{'0','1','1','0','0','0','0'}, /* one */
{'1','1','0','1','1','0','1'}, /* two */
{'1','1','1','1','0','0','1'}, /* three */
{'0','1','1','0','0','1','1'}, /* four */
{'1','0','1','1','0','1','1'}, /* five */
{'1','0','1','1','1','1','1'}, /* six */
{'1','1','1','0','0','0','0'}, /* seven */
{'1','1','1','1','1','1','1'}, /* eight */
{'1','1','1','0','0','1','1'}};/* nine */
char digits[3][MAX_DIGITS * 4]; /* digits array */
int i, j; /* count variables */
int adjust; /* output formatting */
int main(void) {
clear_digits_array();
int digit[20];
for (i = 0; i < 20; i++) {
digit[i] = 0;
}
int count = 20;
int position = 0;
printf("Enter a number: ");
int number = scanf("%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
&digit[0],
&digit[1],
&digit[2],
&digit[3],
&digit[4],
&digit[5],
&digit[6],
&digit[7],
&digit[8],
&digit[9],
&digit[10],
&digit[11],
&digit[12],
&digit[13],
&digit[14],
&digit[15],
&digit[16],
&digit[17],
&digit[18],
&digit[19]); //NOTHING HAPPENS AFTER HERE
printf("Got input, number is %d", number);
while (count > 0) {
printf("Reading digits, count is %d", count);
process_digit(digit[20 - count], position);
position++;
count--;
}
print_digits_array();
printf("\n");
return 0;
}
void clear_digits_array(void) {
/* fill all positions in digits array with blank spaces */
for (i = 0; i < 3; i++) {
for (j = 0; j < (MAX_DIGITS * 4); j++) {
digits[i][j] = ' ';
}
}
}
void process_digit(int digit, int position) {
/* check each segment to see if segment should be filled in for given digit */
for (i = 0; i < 7; i++) {
printf("Processing digit %d at position %d, i is %d", digit, position, i);
if (segments[digit][i] == 1) {
switch (i) {
case 0: digits[0][(position * 4) + 1] = '_';
break;
case 1: digits[1][(position * 4) + 2] = '|';
break;
case 2: digits[2][(position * 4) + 2] = '|';
break;
case 3: digits[2][(position * 4) + 1] = '_';
break;
case 4: digits[2][(position * 4) + 0] = '|';
break;
case 5: digits[1][(position * 4) + 0] = '|';
break;
case 6: digits[1][(position * 4) + 1] = '_';
break;
}
}
}
}
void print_digits_array(void) {
/* print each character in digits array */
for (i = 0; i < 3; i++) {
for (j = 0; j < (MAX_DIGITS * 4); j++) {
printf("%c", digits[i][j]);
}
printf("/n");
}
}
Your code includes:
printf("Enter a number: ");
int number = scanf("%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
&digit[0],
&digit[1],
&digit[2],
&digit[3],
&digit[4],
&digit[5],
&digit[6],
&digit[7],
&digit[8],
&digit[9],
&digit[10],
&digit[11],
&digit[12],
&digit[13],
&digit[14],
&digit[15],
&digit[16],
&digit[17],
&digit[18],
&digit[19]); //NOTHING HAPPENS AFTER HERE
Have you entered twenty separate digits? If not, scanf() is waiting for you to type some more numbers.
Note that the return value from scanf() is the number of successfully converted numbers (0..20 in the example), not the value you entered.
Is that the issue? I tried to make it such that the maximum amount of numbers the user could enter was 20, and if any more were entered they would be ignored, or if fewer were entered, it would only consider those (say, 5 were entered, then only the 5 would be used). Is there an easier way to do this sort of thing then?
Yes, I think that's the issue.
There are probably several easier ways to do it. I'd be tempted to use:
char buffer[22]; // 20 digits, newline, null
if (fgets(buffer, sizeof(buffer), stdin) != EOF)
{
size_t len = strlen(buffer);
if (len >= sizeof(buffer) - 1)
{
fprintf(stderr, "You entered too long a string (maximum 20 digits)\n");
exit(EXIT_FAILURE);
}
if (len > 0)
buffer[--len] = '\0'; // Zap newline — carefully
for (int i = 0; i < len; i++)
{
if (!isdigit(buffer[i]))
{
fprintf(stderr, "Non-digit %c found\n", buffer[i]);
exit(EXIT_FAILURE);
}
}
...and from here, process the digits in buffer, one at a time...
...Use buffer[i] - '0' to get a number 0..9 from the character in buffer...
}
Another option is to use a long long number, but that only gives you up to 18 digits (signed) or 19 digits (unsigned), with some values of 19 or 20 also within range. You'd then strip the digits out of the number using division and modulus operations.
long long value;
if (scanf("%lld", &value) == 1)
{
if (value < 0)
...error processing...
do
{
int digit = value % 10;
value /= 10;
...process digit...
} while (value > 0);
}
This has some merits, but in practice, I'd be tempted to use fgets() to read a line of input, and either sscanf() or strtoll() to convert and validate the number. That isn't as simple as it looks; the error returns from strtoll(), in particular, are many and subtle, and none of the scanf() family handle overflowing numbers gracefully. You could constrain the scanf() though with %18lld so that no more than 18 digits are read, but that would mean that if the user typed 19 or more digits, you'd get the leftovers on the next attempt to read with scanf(). So, handling scanf() is not simple either, especially if you need to convert multiple numbers in a single run of the program.
With those caveats out of the way, you can usually do a 'good enough' job with a sensible person providing the input. It is the process of making a program bomb-proof (foolproof — as in, proof against fools) that is hard. I find meaningful error reporting easier when I can report the whole string that was read in (as with fgets()); with scanf(), you can't see the characters that were entered and consumed before something went wrong.
use GDB, here is introduction for it http://www.gnu.org/software/gdb/
look into this tutorial too http://www.cs.cmu.edu/~gilpin/tutorial/
int number = scanf("%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
&digit[0],
&digit[1],
&digit[2],
&digit[3],
&digit[4],
&digit[5],
&digit[6],
&digit[7],
&digit[8],
&digit[9],
&digit[10],
&digit[11],
&digit[12],
&digit[13],
&digit[14],
&digit[15],
&digit[16],
&digit[17],
&digit[18],
&digit[19]);
I don't think this is a good idea use loop here
for (i = 0; i < 20; i++)
scanf("%d",&digit[i]);
And if you need the number
then do like this
int number = i; when loop finishes.
You can also try this
char buf[12];
while((c=getchar())!=EOF && i < 20)
{
buf[j++] =c;
if((c == '\n' || c == ' ' || c == '\t') && (sscanf(buf,"%d",&digit[i])) == 1)
{
i++;
j = 0;
}
}
For EOF you will have to press CTRL+D
In this way you can take 20 or less integers