Array with stopping condition - c

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

Related

C language - counting number of different vowels with no pointers or additional functions

I got this exercise that I haven't been able to solve, the point is to create a program where you type in a text, then the program analyzes each word of the text and counts the vowels of each word, then the program returns in screen the number of words that have 3 or more different vowels, and by different I mean, it doesn't matter if the word has 3 "a", it only count as one (the word has the vowels "a", it doesn't matter how many times), so for example, the word "above" has 3 vowels, the word "been" has 1 vowels, the word "example" has 2 vowels. The vowels can be upper case or lower case, it doesn't matter, and here is the tricky part: It cannot contain any pointers or functions made by us.
what i did was asking the user to enter word by word so the program analyze each word, and then at the end returns the number of words that contain 3 or more vowels, but I feel like there must be an easier way where the user can type a complete paragraph or text, then the program analyzes each word and return the number of words that have 3 or more different vowels.
Anyway, my code is as follows, any suggestions would be appreciated:
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
main() {
int vowels, text, words, c, total=0,a=0,e=0,i=0,o=0,u=0;
printf ("How many words does your text has? ");
scanf("%d",&words);
for(c=1;c<=words;c++){
printf("Type your word %d, after that press enter, then press 'control' and 'z' at the same time, and then press enter again: \n", c);
while (EOF != (text=getchar())){
if (text == 'a' || text == 'A'){
a++;
if (a >=2){
a = 1;
}
}
if (text == 'e' || text == 'E'){
e++;
if (e >=2){
e = 1;
}
}
if (text == 'i' || text == 'I'){
i++;
if (i >=2){
i = 1;
}
}
if (text == 'o' || text == 'O'){
o++;
if (o >=2){
o = 1;
}
}
if (text == 'u' || text == 'U'){
u++;
if (u >=2){
u = 1;
}
}
}
vowels = a+e+i+o+u;
if(vowels >=3){
total = total +1;
}
a=0,e=0,i=0,o=0,u=0;
vowels = 0;
}
printf("\n\nThe total of words with 3 or more vowels is: %d", total);
printf("\n");
total=0;
return 0;
}
In order to read and analyze a single word, or a paragraph words to determine the number of words that contain at least three different vowels (of any case), this is one of the rare times when reading input with scanf (using the '%s' format specifier) actually is a reasonable choice.
Recall the '%s' format specifier will read characters up to the first whitespace. That gives you a simple way to read a word at a time from stdin. To end input, the user simply need to generate an EOF by entering ctrl+d (or ctrl+z on windows). This satisfies your paragraph requirement.
For parsing, you can take advantage of converting each character to lower case to simplify checking for vowels. Using a frequency array of 5 elements provides a simple way to track the number of different vowels found in each word. Then a final test to see if the number of vowels found equals the required number is all you need before incrementing your total word count for words with three different vowels.
A simple implementation would be something similar to:
#include <stdio.h>
enum { NREQD = 3, NVOWEL = 5, MAXC = 128 }; /* declare constants */
int main (void) {
char word[MAXC] = ""; /* word buffer */
size_t wordcnt = 0; /* words with 3 different vowels */
printf ("enter a word(s) below, [ctrl+d on blank line to end]\n");
for (;;) {
int vowels[NVOWEL] = {0}, /* frequency array */
vowelcnt = 0, /* vowels per-word */
rtn; /* scanf return */
if ((rtn = scanf ("%127s", word)) == EOF) /* chk EOF */
break;
for (int i = 0; word[i]; i++) { /* loop over each char */
if ('A' <= word[i] && word[i] <= 'Z') /* check upper */
word[i] ^= 'a' - 'A'; /* convert to lower */
switch (word[i]) { /* check if vowel */
case 'a': vowels[0] = 1; break;
case 'e': vowels[1] = 1; break;
case 'i': vowels[2] = 1; break;
case 'o': vowels[3] = 1; break;
case 'u': vowels[4] = 1; break;
}
}
for (int i = 0; i < NVOWEL; i++) /* loop over array */
if (vowels[i]) /* check index */
vowelcnt++; /* increment vowelcnt */
if (vowelcnt >= NREQD) /* do we have at least 3 vowels? */
wordcnt++; /* increment wordcnt */
}
printf ("\nThere are %zu words with %d different vowels.\n",
wordcnt, NREQD);
}
Example Use/Output
$ ./bin/vowelcnt
enter a word(s) below, [ctrl+d on blank line to end]
Everyone Understands That The Dictionary Doesn't Track
Words That Contain Vowels Like It Does Etimology.
There are 4 words with 3 different vowels.
Look things over and let me know if you have further questions.
You can use fgets to read a whole line. I don't know how you define a
paragraph though, do you mean just a long text or a collection of lines? You can
copy & paste multiple lines in the console and if you loop using fgets, then
you get all the lines. But allowing the user to enter multiple lines at once,
it's more tricky, because you should know how many lines the user will input.
That's why I'd say focus on reading the text line by line.
Your solution reads characters by characters and you are ignoring non-vowels.
That's OK, but you are not detecting words like you should do. The for loop
makes no sense, because in the first iteration you enter in a while loop that
is only going to leave when there are no more characters to read from stdin.
So the next iteration of the for loop will not enter the while loop and you
won't be reading anything any more.
You are also repeating too much code, I know you assignment says not to use your
own functions, but this can be improved with a simple look up table by creating
an array of chars using the characters as an index for the array. I'll explain
that in the code.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
int main(void)
{
char line[1024];
// initializing look ups with 0
int lookup_vowels[1 << CHAR_BIT] = { 0 };
// using 'a', 'e' as index for the lookup table
// if you want to know if a character is a vowel,
// lookup_vowels[character] will be 1 if character is
// a vowel, 0 otherwise
lookup_vowels['a'] = lookup_vowels['e'] = lookup_vowels['i'] =
lookup_vowels['o'] = lookup_vowels['u'] = 1;
// for parsing word with strtok
const char *delim = " \t\r\n";
int num_of_words = 0;
printf("Enter some text, to end input press ENTER and then CTRL+D\n");
while(1)
{
if(fgets(line, sizeof line, stdin) == NULL)
break;
// parsing words
char *word = strtok(line, delim);
if(word == NULL)
continue; // the line has only delimiters, ignore it
do {
// will be access with the same principle as the lookup
// table, the character is the index
int present[1 << CHAR_BIT] = { 0 };
size_t len = strlen(word);
for(size_t i = 0; i < len; ++i)
{
// I'll explain later the meaning
int c = tolower(word[i]);
if(lookup_vowels[c])
present[c] = 1; // set the present for a vowel to 1
}
int count = present['a'] + present['e'] + present['i'] + present['o']
+ present['u'];
if(count > 2)
{
printf("'%s' has more than three distinct vowels\n", word);
num_of_words++;
}
} while((word = strtok(NULL, delim)));
}
printf("The number of word with three or more distinct vowels: %d\n", num_of_words);
return 0;
}
So let me quickly explain some of the technique I use here:
The lookup table is an array of size 256 because a char is 8-bit1
value and can have 256 different values (range [0,255]). The idea is that this
array is initialized with 0 overall (int lookup_vowels[1<<CHAR_BIT] = { 0 };) and then
I set to 1 only in 5 places: at the position of the vowels using their
ASCII value as index.
So instead of doing the repeating task if checking
// where c is a char
if(c == 'a' || c == 'A')
a=1;
}
for all vowels, I just can do
int idx = tolower(c);
if(lookup_vowels[idx])
{
// c is a vowel
}
The present variable function similar to the lookup table, here I use the
ASCII code of a vowel as index and set it to 1 if a vowel is present in word.
After scanning all characters in word, I sum all values stored in present.
If the value is greater than 2, then the word has at least 3 or more distinct
vowels and the counter variable is increased.
The function strtok is used to split the line using a defined set of
delimiters, in this case the empty character, tab, carriage return and line
feed. To start parsing the line, strtok must be called with the source string
as the first argument and the delimiters as the second argument. All other
subsequent calls must pass NULL as the first argument. The function returns a
pointer to the next word and returns NULL when no more words have been found.
When a word is found, it calculates the number of distinct vowels and checks if
this number is greater than 2.
fotenotes
1CHAR_BIT defined in limits.h returns the number of bits of byte.
Usually a byte is 8-bit wide, so I could have written 256 instead. But there are
"exotic" architectures where a byte is not 8-bit long, so by doing 1<<CHAR_BIT
I'm getting the correct dimension.

How to exit stdin when EOF is reached in C programming

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).

How to scan in values and ignore the characters

I am a newbie to C and I was looking over some questions where I pondered upon a question where we need to scan in values using the users input. Example
1 2 3 45 6 7. So Automatically we scan these values into a 2D array.
One thing that troubles me is what If the user inputs
1 2 3 2 3 Josh, how can we ignore Josh and only scan in the values into the array.
I looked at using getchar and use a flag variable but I am unable to figure out the conundrum of differentiating between the integer and character.
/* This is something that I tried */
#include <stdio.h>
int main(int argc, char *argv[]) {
int a;
int b;
int A[10];
while (((a = getchar()) != '\n') && (b = 0)) {
if (!(a >= "A" && a <= "Z")) {
scanf("%d", A[b]);
}
b++;
}
}
}
I think one good method for achieving what you want is using scanf with the format "%s", which will read everything as a string, effectively splitting the input according to white spaces. From the manual:
s
Matches a sequence of non-white-space characters; the next
pointer must be a pointer to character array that is long
enough to hold the input sequence and the terminating null
byte ('\0'), which is added automatically. The input string
stops at white space or at the maximum field width, whichever
occurs first.
To convert the string to integer, you can use atoi. From the manual:
The atoi() function converts the initial portion of the string
pointed to by nptr to int.
So, if it converts the initial portion of the string into an integer, we can use that to identify what is a number and what's not.
You can build a simple "word detector" for atoi.
Using the function isalpha from ctype.h you can do:
int isword(char *buffer)
{
return isalpha(*buffer);
}
And rewriting your reading program you have:
#include <stdio.h>
#include <ctype.h>
int isword(char *buffer)
{
return isalpha(*buffer);
}
int main(void)
{
char input[200];
int num;
while (1) {
scanf("%s", input);
if (!strcmp(input, "exit")) break;
if (isword(input)) continue;
num = atoi(input);
printf("Got number: %d\n", num);
}
return 0;
}
You should keep in mind that the name isword is fallacious. This function will not detect if buffer is, in fact, a word. It only tests the first character and if that is a character it returns true. The reason for this is the way our base function itoa works. It will return zero if the first character of the buffer is not a number - and that's not what you want. So, if you have other needs, you can use this function as a base.
That's also the reason I wrote a separate function and not:
if (!isalpha(input[0]))
num = itoa(input);
else
continue;
The output (with your input):
$ ./draft
1 2 3 2 3 Josh
Got number: 1
Got number: 2
Got number: 3
Got number: 2
Got number: 3
exit
$
About assigments and &&
while (((a = getchar()) != '\n') && (b = 0))
As I said in a comment, this loop will never work because you're making a logical conjunction(AND) with an assignment that will always return zero. That means the loop condition will always evaluate to false.
In C, assignments return the value assigned. So, if you do
int a = (b = 10);
a will have now hold the value 10. In the same way, when you do
something && (b = 0)
You're effectively doing
something && 0
Which will always evaluate to false (if you remember the AND truth table):
p q p && q
---------------
0 0 0
0 1 0
1 0 0
1 1 1
Your code is completely wrong. I suggest to delete it.
You could use scanf with %d to read in numbers. If it returns 0, there is some invalid input. So, scan and discard a %s and repeat this process:
int num = -1;
while(num != 0)
{
printf("Enter a number, enter 0 to exit:");
if(scanf("%d", &num) == 0) /* If scanf failed */
{
printf("Invalid input found!");
scanf("%*s"); /* Get rid of the invalid input (a word) */
}
}

Scanf and two strings

My task is read two strings of digits and save them in different arrays.
I decided to use scanf function, but program can read only first string.
This is my bad-code.
int main()
{
int firstArray[50], secondArray[50], i, j;
/* fill an array with 0 */
for(i=0; i<50; ++i)
{
firstArray[i]=secondArray[i]=0;
}
i=j=0;
while((scanf("%d", &firstArray[i]))== 1) { ++i; }
while((scanf("%d", &secondArray[j]))== 1) { ++j; }
/* Print this. */
for(i = 0; i < 20; ++i)
{
printf("%d ", firstArray[i]);
}
putchar('\n');
for(j = 0; j < 20; ++j)
{
printf("%d ", secondArray[j]);
}
return 0;
}
I just don't understand how scanf function works. Can someone please explain?
scanf ignores blank characters (including new line). Thus your scan will read entire input into firstArray if you have no "non blank" separator.
If file/data has ; at end of first line it will stop the read into firstArray there, and never read anything into secondArray - as you never consume the ;.
/* This will never be 1 as ; is blocking */
while((scanf("%d", &secondArray[i])) == 1) {
So: if you separate with i.e. ; you will have to read / check for this before you read into secondArray.
You could also add something like:
char c;
/* this can be done more tidy, but only as concept */
while((scanf("%d", &firstArray[i])) == 1 && i < max) {
++i;
if ((c = getchar()) == '\n' || c == ';')
break;
}
Also instead of initializing array to 0 by loop you can say:
int firstArray[50] = {0}; /* This set every item to 0 */
Also take notice to ensure you do not go over your 50 limit.
You say strings of digits and you read %d. The format scans the input for the longest sequence representing an integer (signed) value. Two "digit strings" are consumed by the first while loop.
EDIT Instead of "strings of digits" you should say "strings of integers". In this case it is a little bit more subtle since the first while can consume all the integers, unless they are separated by something that is not a possible integer (e.g. a ;).
So, to make the following to work, you must separate the two "lines" with something that can't be parsed as integer and which is not considered "white character". Not the better solution, but one the possible.
#include <stdio.h>
#include <ctype.h>
int main()
{
int firstArray[50] = {0};
int secondArray[50] = {0};
int i, j, l1, l2;
int tmp;
i = j = 0;
// read integers, but not more than size of array
while( scanf("%d", &firstArray[i]) == 1 && i < sizeof(firstArray) ) {
++i;
}
// consume non digits
for(tmp = getchar(); tmp != EOF && !isdigit(tmp); tmp = getchar());
// on EOF you should exit and stop processing;
// we read one more char, push it back if it was a digit
if (isdigit(tmp)) ungetc(tmp, stdin);
while( scanf("%d", &secondArray[j]) == 1 && j < sizeof(secondArray) ) {
++j;
}
l1 = i; // preserve how many ints were read
l2 = j;
/* Print this. */
for(i = 0; i < l1; ++i)
{
printf("%d ", firstArray[i]);
}
putchar('\n');
for(j=0; j < l2; ++j)
{
printf("%d ", secondArray[j]);
}
return 0;
}
EDIT A solution that maybe fits your need better is to read the lines (one per time) into a buffer and sscanf the buffer.
You cannot use scanf to do that.
Read the documentation.
Observations:
with scanf if you enter a digit your loop runs forever
there is no check on size 50 limit of your arrays
if you press return then it ignores that line because does not match your pattern
if you enter a letter the pattern does not match and loop breaks
So use some other function, maybe gets, atoi or strtol. And remember to check the size 50 limit of your arrays.
Actually, there is one special point in C's arrays.
Though you declare an array's size. say int arr[5]; You can store values beyond the size of 5. It doesn't show any error but leads to undefined behavior (Might overwrite other variables).
Please Refer this question: Array size less than the no. of elements stored in it
In you case, that was your problem. The compiler had never passed beyond the first while statements. Thus, you didn't get any output. In fact, it didn't even compile the whole code yet!
while((scanf("%d", &firstArray[i]))== 1) { ++i; }
So, you could write this while statement like this:
while( scanf("%d", &firstArray[i]) ==1 && i<50 )
i++;
or else:
while(i<50 )
{
scanf("%d", &firstArray[i]);
i++;
}
or else:
for (i=0; i<50; i++)
scanf("%d", &firstArray[i]);

Putting numbers separated by a space into an array

I want to have a user enter numbers separated by a space and then store each value as an element of an array. Currently I have:
while ((c = getchar()) != '\n')
{
if (c != ' ')
arr[i++] = c - '0';
}
but, of course, this stores one digit per element.
If the user was to type:
10 567 92 3
I was wanting the value 10 to be stored in arr[0], and then 567 in arr[1] etc.
Should I be using scanf instead somehow?
There are several approaches, depending on how robust you want the code to be.
The most straightforward is to use scanf with the %d conversion specifier:
while (scanf("%d", &a[i++]) == 1)
/* empty loop */ ;
The %d conversion specifier tells scanf to skip over any leading whitespace and read up to the next non-digit character. The return value is the number of successful conversions and assignments. Since we're reading a single integer value, the return value should be 1 on success.
As written, this has a number of pitfalls. First, suppose your user enters more numbers than your array is sized to hold; if you're lucky you'll get an access violation immediately. If you're not, you'll wind up clobbering something important that will cause problems later (buffer overflows are a common malware exploit).
So you at least want to add code to make sure you don't go past the end of your array:
while (i < ARRAY_SIZE && scanf("%d", &a[i++]) == 1)
/* empty loop */;
Good so far. But now suppose your user fatfingers a non-numeric character in their input, like 12 3r5 67. As written, the loop will assign 12 to a[0], 3 to a[1], then it will see the r in the input stream, return 0 and exit without saving anything to a[2]. Here's where a subtle bug creeps in -- even though nothing gets assigned to a[2], the expression i++ still gets evaluated, so you'll think you assigned something to a[2] even though it contains a garbage value. So you might want to hold off on incrementing i until you know you had a successful read:
while (i < ARRAY_SIZE && scanf("%d", &a[i]) == 1)
i++;
Ideally, you'd like to reject 3r5 altogether. We can read the character immediately following the number and make sure it's whitespace; if it's not, we reject the input:
#include <ctype.h>
...
int tmp;
char follow;
int count;
...
while (i < ARRAY_SIZE && (count = scanf("%d%c", &tmp, &follow)) > 0)
{
if (count == 2 && isspace(follow) || count == 1)
{
a[i++] = tmp;
}
else
{
printf ("Bad character detected: %c\n", follow);
break;
}
}
If we get two successful conversions, we make sure follow is a whitespace character - if it isn't, we print an error and exit the loop. If we get 1 successful conversion, that means there were no characters following the input number (meaning we hit EOF after the numeric input).
Alternately, we can read each input value as text and use strtol to do the conversion, which also allows you to catch the same kind of problem (my preferred method):
#include <ctype.h>
#include <stdlib.h>
...
char buf[INT_DIGITS + 3]; // account for sign character, newline, and 0 terminator
...
while(i < ARRAY_SIZE && fgets(buf, sizeof buf, stdin) != NULL)
{
char *follow; // note that follow is a pointer to char in this case
int val = (int) strtol(buf, &follow, 10);
if (isspace(*follow) || *follow == 0)
{
a[i++] = val;
}
else
{
printf("%s is not a valid integer string; exiting...\n", buf);
break;
}
}
BUT WAIT THERE'S MORE!
Suppose your user is one of those twisted QA types who likes to throw obnoxious input at your code "just to see what happens" and enters a number like 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 which is obviously too large to fit into any of the standard integer types. Believe it or not, scanf("%d", &val) will not yak on this, and will wind up storing something to val, but again it's an input you'd probably like to reject outright.
If you only allow one value per line, this becomes relatively easy to guard against; fgets will store a newline character in the target buffer if there's room, so if we don't see a newline character in the input buffer then the user typed something that's longer than we're prepared to handle:
#include <string.h>
...
while (i < ARRAY_SIZE && fgets(buf, sizeof buf, stdin) != NULL)
{
char *newline = strchr(buf, '\n');
if (!newline)
{
printf("Input value too long\n");
/**
* Read until we see a newline or EOF to clear out the input stream
*/
while (!newline && fgets(buf, sizeof buf, stdin) != NULL)
newline = strchr(buf, '\n');
break;
}
...
}
If you want to allow multiple values per line such as '10 20 30', then this gets a bit harder. We could go back to reading individual characters from the input, and doing a sanity check on each (warning, untested):
...
while (i < ARRAY_SIZE)
{
size_t j = 0;
int c;
while (j < sizeof buf - 1 && (c = getchar()) != EOF) && isdigit(c))
buf[j++] = c;
buf[j] = 0;
if (isdigit(c))
{
printf("Input too long to handle\n");
while ((c = getchar()) != EOF && c != '\n') // clear out input stream
/* empty loop */ ;
break;
}
else if (!isspace(c))
{
if (isgraph(c)
printf("Non-digit character %c seen in numeric input\n", c);
else
printf("Non-digit character %o seen in numeric input\n", c);
while ((c = getchar()) != EOF && c != '\n') // clear out input stream
/* empty loop */ ;
break;
}
else
a[i++] = (int) strtol(buffer, NULL, 10); // no need for follow pointer,
// since we've already checked
// for non-digit characters.
}
Welcome to the wonderfully whacked-up world of interactive input in C.
Small change to your code: only increment i when you read the space:
while ((c = getchar()) != '\n')
{
if (c != ' ')
arr[i] = arr[i] * 10 + c - '0';
else
i++;
}
Of course, it's better to use scanf:
while (scanf("%d", &a[i++]) == 1);
providing that you have enough space in the array. Also, be careful that the while above ends with ;, everything is done inside the loop condition.
As a matter of fact, every return value should be checked.
scanf returns the number of items successfully scanned.
Give this code a try:
#include <stdio.h>
int main()
{
int arr[500];
int i = 0;
int sc = 0; //scanned items
int n = 3; // no of integers to be scanned from the single line in stdin
while( sc<n )
{
sc += scanf("%d",&arr[i++]);
}
}

Resources