Taking as input only numbers and letters with getch() in c - c

what I'm trying to accomplish is a simultaneous research by using the fuction getch. I know that this fuction returns a integer value, which represents the ASCII code of a key. Is there any wroten fuction that allows the user to write only certain characters, such as: letters, numbers, and apostrophe.

char c;
int temp = 0;
while((c= getch()) !='\r')
{
if ((temp == -32) || (temp == 0))
{
}
else
{
if(isalnum((char)c) == 0)
{
if((c == '\'') || (c == -118) || (c == -115) || (c == -107) || (c == -123) || (c == -105))
{
printf("true: %c\n",c);
}
else
printf("false: %d\n",c);
}
else
{
printf("true: %c\n",c);
}
}
temp = c;
}
For anyone else who's trying to accomplish the same result, this works fine for me.

Is there any write function that allows the user to write only certain characters, such as: letters, numbers, and apostrophe. (?)
Code can instead selectivity write
#include <ctype.h>
#include <stdio.h>
int c; // use type `int` here to distinguish all (256) characters from EOF
while((c = getch()) != '\r' && c != '\n' && c != EOF) {
if (isalnum(c) || '\'') {
putchar(c);
}
}

Related

How to delete characters except alphabets in c

There is a file "poem.txt":
*The ho$use cat sits.*
*And sm%iles and) sing&s.*
*He% know*(s a l_ot*
*Of s!ecret thi<ngs.*
I need to delete unnecessary symbols from it and write it to another file "poem_modified" without using arrays, functions, structures and pointer and only with <stdio.h> library:
I was able to do it so far:
#include <stdio.h>
int main() {
FILE *input;
FILE *output;
input = fopen ("poem.txt", "r");
output = fopen ("poem_modified.txt", "w");
if (input == NULL || output == NULL)
{
printf("Problem! \n");
return 1;
}
char ch ;
while((ch=getc(input)) != EOF)
fprintf(output, "%c", ch);
fclose(input);
fclose(output);
}
Adding conditions while printing the character can help
Suppose, it is required to include a-z and A-X only with spaces and newline char. So conditions can be made such as if the character is between a-z or between A-Z or it is newline or space, the char will be printed. Otherwise not. Any other conditions can be added.
The getc() function return type is an integer. documentation
Correct indentation helps to understand the code.
#include <stdio.h>
int main() {
FILE *input;
FILE *output;
input = fopen ("poem.txt", "r");
output = fopen ("poem_modified.txt", "w");
if (input == NULL || output == NULL)
{
printf("Problem! \n");
return 1;
}
int ch ;
while((ch=getc(input)) != EOF) {
if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || ch == ' ' || ch == '\n'){
fprintf(output, "%c", ch);
}
}
fclose(input);
fclose(output);
}
output :
The house cat sits
And smiles and sings
He knows a lot
Of secret things
Portability Concerns
Using the > and < operators on characters is not a portable solution for this in C. For the special case of the digits '0'...'9' you can do this because the C Standard specifies that these characters must be encoded contiguously and in ascending order.
It is unlikely that using comparison operators to check whether a character is alphabetic in the manner (ch >= 'A' && ch <= 'Z') will cause problems on most modern systems, but problems do occur. Certainly it could be a problem on older systems, such as legacy systems installed at institutions many years ago. This is exactly why the functions described in ctype.h should usually be preferred: these can be relied upon to work portably.
Portable Solutions
But if this is not possible more portable solutions than the aforementioned char comparison which relies upon a particular character encoding can be had.
Being unable to use arrays is a severe (and artificial) constraint. Of the two solutions below, the first solution does use an array (keepers) to encode characters which should be written to output. There is another solution following which does not use such an array, and I think that it meets all of OP's requirements, yet the second solution is a bit more awkward and error-prone to write.
Both solutions are more portable than using (ch >= 'A' && ch <= 'Z') methods, and both give the same results:
$ cat poem_modified.txt
The house cat sits
And smiles and sings
He knows a lot
Of secret things
Using an Array
The first solution defines an array keepers which is initialized by a string literal to contain all characters which should be written to output. As characters are read from input, the program checks in keepers to see if the character is present in this list; if so it is written to output, and if not the next character is read from input.
#include <stdio.h>
int main(void) {
// Open input file and check for errors
const char *input_file = "poem.txt";
FILE *input = fopen(input_file, "r");
if (input == NULL) {
fprintf(stderr, "Unable to open file %s for input\n", input_file);
return 1;
}
// Open output file and check for errors
const char *output_file = "poem_modified.txt";
FILE *output = fopen(output_file, "w");
if (output == NULL) {
fprintf(stderr, "Unable to open file %s for output\n", output_file);
fclose(input);
return 1;
}
char keepers[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ \n";
for (int ch = fgetc(input); ch != EOF; ch = fgetc(input)) {
// Is `ch` an alphabetic character?
size_t idx = 0;
char keeper = keepers[idx];
while(keeper != '\0') {
if (ch == keeper) {
putc(ch, output);
break;
}
keeper = keepers[++idx];
}
}
fclose(input);
fclose(output);
return 0;
}
Using Brute Force
The second solution does the same thing as the first, but without the array. Here instead of using an array to hold the list of characters which should be kept, an if statement with a very long conditional expression encodes this information.
#include <stdio.h>
int main(void) {
// Open input file and check for errors
const char *input_file = "poem.txt";
FILE *input = fopen(input_file, "r");
if (input == NULL) {
fprintf(stderr, "Unable to open file %s for input\n", input_file);
return 1;
}
// Open output file and check for errors
const char *output_file = "poem_modified.txt";
FILE *output = fopen(output_file, "w");
if (output == NULL) {
fprintf(stderr, "Unable to open file %s for output\n", output_file);
fclose(input);
return 1;
}
for (int ch = fgetc(input); ch != EOF; ch = fgetc(input)) {
// Is `ch` an alphabetic character, space, or newline?
if (ch == 'a' || ch == 'b' || ch == 'c' || ch == 'd' || ch == 'e'
|| ch == 'f' || ch == 'g' || ch == 'h' || ch == 'i' || ch == 'j'
|| ch == 'k' || ch == 'l' || ch == 'm' || ch == 'n' || ch == 'o'
|| ch == 'p' || ch == 'q' || ch == 'r' || ch == 's' || ch == 't'
|| ch == 'u' || ch == 'v' || ch == 'w' || ch == 'x' || ch == 'y'
|| ch == 'z' || ch == 'A' || ch == 'B' || ch == 'C' || ch == 'D'
|| ch == 'E' || ch == 'F' || ch == 'G' || ch == 'H' || ch == 'I'
|| ch == 'J' || ch == 'K' || ch == 'L' || ch == 'M' || ch == 'N'
|| ch == 'O' || ch == 'P' || ch == 'Q' || ch == 'R' || ch == 'S'
|| ch == 'T' || ch == 'U' || ch == 'V' || ch == 'W' || ch == 'X'
|| ch == 'Y' || ch == 'Z' || ch == ' ' || ch == '\n')
{
putc(ch, output);
}
}
fclose(input);
fclose(output);
return 0;
}
You can use the various functions from ctype.h to check if something belongs to a certain category of symbols. For example isalpha checks if a character is a letter and isspace checks if it's a space or new line character etc. By using these two functions in combination, we can chose to only print characters that are either letters or spaces. Example:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main (void)
{
char input[] = "*The ho$use cat sits.*\n"
"*And sm%iles and) sing&s.*\n"
"*He% know*(s a l_ot*\n"
"*Of s!ecret thi<ngs.*\n";
size_t length = strlen(input);
for(size_t i=0; i<length; i++)
{
if(isalpha(input[i]) || isspace(input[i]))
{
putchar(input[i]);
}
}
}
Apart from the ctype.h functions making the code easier to read, manual checks like ch >= 'A' && ch <= 'Z' are strictly speaking not well-defined or portable. Because C doesn't guarantee that letters are placed adjacently in the symbol table (see for example the EBCDIC, which was a format used in the Jurassic era). Also the ctype.h functions might handle "locale-specific" characters outside the classic 7 bit ASCII.

program to count commented characters and words in a C file

I have to count characters and word in comment of a C file, for both single line comments and blocked comment. Here's what I have:
#include <stdio.h>
#define IN = 1
#define OUT = 0
main() {
int c, nc;
nc = 0;
while ((c = getchar()) != EOF) {
if (c == '/') {
if (getchar() == '/')
while (getchar() != '\n')
++nc;
}
}
if (c == '/') {
if (getchar() == '*')
while (getchar() != '/')
++nc;
}
printf("Character Counts: %d\n", nc);
}
It works for every single line comment (//), but it skips the blocked comments (/*...*/). I feel like it never enter the if block for the blocked comment. Much appreciate!
There are multiple problems in your code:
You must specify int as the return type of the main function. The syntax in the question is obsolete.
The definitions of IN and OUT are incorrect. You should either use
#define IN 1
#define OUT 0
or
enum { IN = 1, OUT = 0 };
The first loop consumes all the bytes in standard input, you are at the end of file, so the tests for /*...*/ comments never produce anything.
loops such as while (getchar() != '\n') can run forever if the byte tested is not found before the end of file.
You cannot test // and /*...*/ comments separately as one can hide the other:
//* this is a line comment that does not start a C style one
/* this comment contains a // but stops here */ return 0;
Note also that you should parse C strings and character constants as they may contain // and or /* sequences that do not start a comment.
For a complete solution, you should also handle escaped newlines. Here are some pathological examples:
// this is a line comment that extends \
on multiple \
lines (and tricks the colorizer)
/\
* this is a C comment, but the colorizer missed it *\
/
This problem is non-trivial to solve in the general case, but you can start with simple cases.
Here is a modified version:
#include <stdio.h>
int main() {
int c, cc, nc = 0;
while ((c = getchar()) != EOF) {
if (c == '/') {
if ((cc = getchar()) == '/') {
while ((c = getchar()) != '\n')
nc++;
} else
if (cc == '*') {
while ((cc = getchar()) != EOF) {
if (cc == '*') {
if ((cc = getchar()) == '/')
break;
ungetc(cc, stdin);
}
nc++;
}
}
}
}
printf("Character Counts: %d\n", nc);
return 0;
}
I added code to count the words. It works on few occasions, but it behaves weird when I have space after the slash. For example, // comment... Most of the time, the word count is off by 1.
#include<stdio.h>
#define IN 1
#define OUT 0
int main() {
int c, cc, nc = 0;
int state;
int nw = 0;
state = OUT;
while ((c = getchar()) != EOF) {
if (c == '/') {
if ((cc = getchar()) == '/') {
while ((c = getchar()) != '\n'){
nc++;
if (c == ' ' || c == '\t')
state = OUT;
else if (state == OUT){
state = IN;
nw++;
}
}
}
else if (cc == '*') {
while ((cc = getchar()) != EOF) {
if (cc == ' ' || cc == '\t')
state = OUT;
else if (state == OUT){
state = IN;
nw++;
}
if (cc == '*') {
if ((cc = getchar()) == '/')
break;
ungetc(cc, stdin);
}
nc++;
}
}
}
}
printf("Character Counts: %d\n", nc);
printf("Word Counts: %d\n", nw);
return 0;
}
program to count commented characters and words in a C file
it skips the blocked comments (/.../)
I recommend, at a minimum, to parse code and look for 5 states: normal, in a // comment, in a /* comment, in a "" string literal, in a '' character constant.
// pseudo code
while ((ch = getchar()) != EOF) {
if ch == '/' and next == '/', process `//` comment until end-of-line
elseif ch '/' and next == '*', process `/*` comment until `*/`
elseif ch '"', process string until " (but not \")
elseif ch ''', process constant until ' (but not \')
else process normally
}
To look at the next character, call getchar() and then ungetc() if not as expected.

How to check if a character is inside the scope of a comment in C [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I have to write a program that counts the number of times an operator that returns the address of a variable (&) is found inside a file.
I use this simple loop to do so (do not mind the !feof(p) that raises some questions):
while (!feof(p)){
c = fgetc(p);
if (c=='&') n++; }
However, this does not satisfy my needs. For instance, if an AND operator (&&) is found, my loop will increase the variable "n" twice but it mustn't even once. Another thing is that if the & operator is found in the scope of a single or multi-line comment it should not be counted.
My question is how can I make sure the given character/string (in my case "&" operator) is in a comment or not? And how to make sure it is indeed a "&" operator and not a part of a "&&" or a string?
As been mentioned in the comments, this is not a trivial task that could be written with a few lines of code. What you need is a parser. That parser needs to handle many different cases. Here is a (probably non-exhaustive) list:
One line comments: // This is a comment
Multiline comments: /* This is a comment */
Characters: char c='&'
String literals: strcmp(str, "A string with a & in it")
The bitwise operator: int a = mask & b
You would also need to decide how to handle incorrect input. Should the program be able to detect incorrect c code, or should it assume all input is correct? Another thing to consider is how to handle #include. Do you want to count the number of occurrences in the included files too? (I assume not, but this demonstrates a problem)
If you want it to 100% accurate in finding only the address operator, then it is way above your knowledge. (OP wrote "This is a problem is designed to be solved by 1st-semester students with only basic knowledge." in comment below)
If you're allowed to cut some corners there are easier ways.
Here is a complete example that cut some corners. It handles comments and strings, including escaped characters. However, it does not handle the bitwise operator.
#include <stdio.h>
#include <stdlib.h>
#define INPUT "input.c"
int main()
{
FILE *f;
if ((f = fopen(INPUT, "r")) == NULL)
{
perror (INPUT);
return (EXIT_FAILURE);
}
char c, p=0;
int n=0;
while((c = fgetc(f)) != EOF)
{
if(c == '/' && p == '/') {
while((c = fgetc(f)) != EOF) {
// If we read // then we throw away the rest of the line
if( c == '\n' ) {
break;
}
}
if( c == EOF) {
goto end;
}
}
else if(c == '*' && p == '/') {
// If we read /* then we throw away everything until we have read */
while((c = getc(f)) != EOF) {
if( c == '*' ) {
if((c = getc(f)) != EOF)
if( c == '/')
break;
}
} if ( c == EOF) {
goto end;
}
}
else if(c == '"') {
// Read until end of string
while((c = getc(f)) != EOF) {
if(c == '\\') {
if((c = getc(f)) == EOF)
goto end;
}
else if(c == '"')
break;
}
}
else if(c == '\'') {
while((c = getc(f)) != EOF) {
if(c == '\\') {
if((c = getc(f)) == EOF)
goto end;
}
else if(c == '\'')
break;
} if ( c == EOF)
goto end;
}
else if(c == '&') {
printf("hej");
if(p == '&')
n--;
else
n++;
}
p=c;
}
end:
printf("\n\nExited at pos %ld\n", ftell(f));
printf("Number of address operators: %d\n", n);
}
It works a bit like this: When it sees a start of a comment, it reads and throws away everything until the comment is finished or EOF. It does the same for strings.
On this input:
// Test &
/* Also
&
test */
// "
int main()
{
/* " //
*/
// /*
char str[]="hej&\"";
char c='&';
char k='\'';
int a, b;
int * p;
p=&a;
int c=a&b;
int q=a&&b;
}
// Test &
/* Also
&
test */
It reports the expected result 2. It would be better if it printed 1, but as I mentioned, it cannot handle the bitwise operator, thus counting it as an address operator. Fixing this issue would make things a lot more complicated.
And yes, I'm using goto since it is extremely convenient in a situation like this. In C++, I'd use exceptions, but that's not an option in C.
To cover all the cases in the C language would be pretty hard and you would need a proper parser probably, but if you only intend to use this for excersise - to make in work in the cases described in the question, you could implement something like this:
char previous = 0;
int single_line_comment = 0;
int multi_line_comment = 0;
int in_string = 0;
int in_char = 0;
while (!feof(p)){
c = fgetc(p);
if (c == '&' && !single_line_comment && !multi_line_comment && !in_string && !in_char)
{
if(previous == '&')
n--;
else
n++;
}
else if(c == '/' && prev == '/' && !multi_line_comment && !in_string && !in_char)
single_line_comment = 1;
else if(prev == '/' && c == '*' && !single_line_comment && !in_string && !in_char)
multi_line_comment = 1;
else if(c == '\n' && !multi_line_comment && !in_string && !in_char)
single_line_comment = 0;
else if(prev == '*' && c == '/' && !single_line_comment && !in_string && !in_char)
multi_line_comment = 0;
else if(c = '"' && !single_line_comment && !multi_line_comment && !in_char)
in_string = !in_string;
else if(c = '\'' && !single_line_comment && !multi_line_comment && !in_string)
in_char = !in_char;
previous = c;
}
Of course this is not a prefect solution, but could give an idea of how to overcome some of the problems.

K&R C Histogram

I'm currently doing exercise 1-13 in K&R's C the Programming Language 2nd edition. I decided to start with a simple histogram that just replaces each letter in a word with '*'.
#include <stdio.h>
// histogram
#define IN 1
#define OUT 0
main() {
int c, state;
state = OUT;
while ((c = getchar()) != EOF) {
if (c == '\n' || c == '\t' || c == ' ') {
state = OUT;
putchar('\n');
}
else {
if (c != '\n' || c != ' ' || c != '\t') {
state = IN;
putchar('*');
}
}
}
}
However, take a look at this snippet of code:
else {
if (c != '\n' || c != ' ' || c != '\t') {
state = IN;
putchar('*');
}
}
How come this works, but if I enter if (state != OUT) , it doesn't work? I end up getting a completely different output. Aren't those two statements essentially the same thing?
c being equal to three terms "or" each other is not equivalent c not being equal to the negations of the same three terms "or" each other.
See De Morgan's laws.

Printing Uppercase/Lowercase letters

I'm doing a program that is asking the user to enter a stream of characters and printing out the number of uppercase and lowercase letters. I'm trying to do it with a function, but having some trouble printing it..for every character input im entering im getting 0, 0
Would appreciate your help to understand what am I doing wrong:
#include <stdio.h>
#include <ctype.h>
int case_letters(int ch);
int main(void)
{
int x;
printf("please enter a some characters, and ctrl + d to see result\n");
case_letters(x);
return 0;
}
int case_letters(int ch)
{
int numOfUpper = 0;
int numOfLower = 0;
while ((ch = getchar()) != EOF)
{
if ((ch = isdigit(ch)) || ch == '\n')
{
printf("please enter a valid character\n");
continue;
}
else if ((ch = isupper(ch)))
{
numOfUpper++;
}
else if ((ch = islower(ch)))
{
numOfLower++;
}
}
return printf("%d, %d", numOfUpper, numOfLower);
}
All of your if statements assign different value to ch and do not check ch's value.
For example, if you enter a correct char, this
if ((ch = isdigit(ch)) || ch == '\n')
will assign 0 to ch, because isdigit(ch) will return 0. I guess you need
if ( isdigit(ch) || ch == '\n')
Same for islower and isupper.
if ((ch = isdigit(ch)) || ch == '\n')
^-- assignment, not equality test.
You're trashing the value of ch with the return value of isdigit(), and isupper(), and islower(), so that the original user-entered value is destroyed as soon as you do the isdigit test.
Try
if (isdigit(ch) || ch == '\n')
else if (isupper(ch))
else if (islower(ch))
instead. No need to preserve the iswhatever values.

Resources