void input_and_counting_vowels(unsigned short max) { unsigned short ctr = 0, x = 0, y = 0; unsigned short count_vowels = 0, count_consonants = 0; char ch = 0; unsigned char vowels[5+1]; unsigned char consonants[max+1]; for(ctr = 0; ctr < max; ctr++) { printf("\tВведите %2hu символ из %2hu: ", ctr+1, max); if((ch = getchar()) == EOF) { fputs("\nПроизошел сбой при вводе символа!\n", stderr); exit(EXIT_FAILURE); } if(ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') { vowels[x] = ch; x++; count_vowels++; } else if(ch == 'A' || ch == 'E' || ch == 'I' || ch == 'O' || ch == 'U') { vowels[x] = ch; x++; count_vowels++; } else { consonants[y] = ch; y++; } clear_stdin(); } vowels[x] = '\0'; consonants[y] = '\0'; count_consonants = max - count_vowels; printf("\nВы ввели %hu символов.\n", max); printf("\tГласных: %s (%hu).\n", vowels, count_vowels); printf("\tСогласных: %s (%hu).\n", consonants, count_consonants); } 

max - the number of characters entered by the user. My function is clear_stdin () instead of fflush (stdin), since fflush () for some reason does not work.

The vowels [], consonants [] arrays store all the vowels and consonants entered by the user, respectively. +1 for the end of line character to output an array as a string.

Questions:

  1. Is it possible to allocate memory for arrays in some way (vowels [], consonants [])?
  2. Is there another way to count vowels and consonants?
  3. Why does Microsoft Visual C ++ 2010 Express swear by max (requires constant expression)? Whereas gcc in cygwin compiles without problems.
  4. Is it possible to improve this function in general?

I am still studying C (this is my first programming language), so tips, recommendations and constructive criticism are welcome.

  • one
    @dr_kraken, the first error is that the char ch compared to the EOF in the if . In the cp1251 encoding (Russians in Windows) this is the letter 'I'. What happens if more than 5 vowels are entered? ( The vowels [] array will overflow and rub something in memory. ) - Probably, if you want to store and then separately type the entered vowels and so on, you need either 2 arrays of max + 1 size, or one of max + 2 which is filled from two ends (towards each other), and then one of the ends is reversed. Unnecessary +2 - this is for zeroes that fill the character strings (if you type laziness in the loop yourself). - avp
  • Generally, just for counting, 2 variables are n_vowels - n_vowels and total . - In M $, obviously, in some of the max already somehow defined (most likely it is a macro or a function). - Further it is supposed that speech about single-byte characters. If you want to store information exactly which characters were entered at least once - 256 bits are enough (line 16 bytes). If you need to know how many times each character has been entered (order is not important), then an array of 256 counters is enough. Naturally, before use, both must be initialized. - avp
  • one
    @dr_kraken: Yes. But this is -1 type int , and if you assign it to char 'y, it is converted to 255, which corresponds to Russian 'я' in one of the encodings. The getchar() function returns int for a reason. - VladD
  • 2
    > Does getchar () when reaching the end of the file or an error does not return an EOF, which is defined as -1 This is a standard error: getchar() returns an int , and you have a variable of type char . Never use char where int assumed. In this example, int(-1) is not char(-1) , it is 255, it is 0xFF. - user6550 pm
  • one
    @dr_kraken, about EOF and int @VladD you already wrote. If we suck specifically, write int ch; // exactly int, not char !!! About 2) and 3). Eeeeee ... It seems to have already written in the comments. Once again 2) - depends on what you call counting. and 3) - swears, because the variable name intersects with the symbol (variable, constant function name, etc.) already defined in Microfoft files - About the effective memory consumption and input of an arbitrary (total to MAX) quantity - also wrote - - fill one array from two ends (i - increase, j - reduce). - avp

1 answer 1

Uzhoz-Uzhoz. Just look at the first line of code (with the name of the function) to understand what your main problem is. It is impossible to assign two different tasks to the function - input of characters and their counting. And counting in your case is also divided into two tasks: filling in arrays and counting itself. All this should be divided into separate functions.

That's how I would have done the extraction of characters, if I understood the assignment correctly. Notice that the extract_symbols function doesn’t know how the lines were entered, and it doesn’t worry about whether these lines really are, whether they are enough, etc. This is called the principle of sole duty. The function should be responsible only for its work.

 #include <string.h> #include <stdio.h> char* extract_symbols(const char* const list, char* in, char* const out) { char* cur = out; *cur = '\0'; while( *in ) { if( strchr(list, *in) ) { *cur = *in; ++cur; *cur = '\0'; } ++in; } return out; } #define BUF_SIZE 100 int main(void) { char input[BUF_SIZE]; char output[BUF_SIZE]; do { fflush(stdin); fgets(input, sizeof(input), stdin); puts(extract_symbols("aeiou", input, output)); puts(extract_symbols(".,;!?", input, output)); } while( output[0] ); return 0; } 
  • one
    Why *cur = '\0' at each iteration? Where is the input size out ? Wah-wah :) - user6550
  • @VadimTukaev Thank you. This code is a bit complicated for me, I will understand. Ps. Your program does not display consonants, and does not count the number of those and others. And I liked it, compact and elegant. It would be ideal if added comments / explanations. - dr_kraken
  • @VadimTukaev, in general, initially the TC divided the characters into vowels and all the rest , and also counted (and printed) the number of both. You'll have to modify extract_symbols() bit. Interestingly, how many times (assuming the initial pass through the characters of the file to '\n' ) will have to refer to each character as part of the requirement that the program should be broken down into functions, each of which performs strictly one task. - Well, such an input cycle does not work at all (at least you don’t process EOF). - avp
  • 3
    cur is not a pointer to a pointer! This is a pointer that refers to the same memory as out . And it is needed in order to be able to return out of the function (without an additional pointer, we would increase out loop, and after the end of the loop, it would stop referring to the beginning of the line, which we want to return). As for const * const , one prohibits modifying the data referenced by the pointer. Another prohibits modifying the pointer itself. Do you read the textbooks for sure? Just in case, take a look here: habrahabr.ru/post/59558 - user6550
  • one
    @dr_kraken, you need to understand that this solution is not at all your task. Just a demonstration of some language features ( keyword const ) that allow the compiler to detect some errors (mismatch between implementation and specification), but really little impact on the effectiveness of practical programming. - By the way, IMHO like this char * cur = out; for (; * in; in ++) if (strchr (list, * in)) // strchr () finds the character in the string (see man) * cur ++ = * in; * cur = 0; return out; much more compact (and in my opinion, more understandable). - avp