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.
Related
This code contains 3 file handling related functions which read from a file named "mno". But only the 1st called function in the main() is working. If the 1st function of the list is commented then, only the 2nd function will work and the third won't. Same goes for the 3rd one
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
void countVowel(char fin[])
{
FILE *fl;
char ch;
int count = 0;
fl = fopen(fin, "r");
while (ch != EOF)
{
ch = tolower(fgetc(fl));
count += (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') ? 1 : 0;
}
fclose(fl);
printf("Number of Vowels in the file \" %s \"-> \t %d \n", fin, count);
}
void countConsonant(char fin[])
{
FILE *fl;
char ch;
int count = 0;
fl = fopen(fin, "r");
while (ch != EOF)
{
ch = tolower(fgetc(fl));
count += (!(ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') && (ch >= 'a' && ch <= 'z')) ? 1 : 0;
}
fclose(fl);
printf("Number of Consonant in the file \" %s \"-> \t %d \n", fin, count);
}
void countAlphabet(char fin[])
{
FILE *fl;
char ch;
int count = 0;
fl = fopen(fin, "r");
while (ch != EOF)
{
ch = tolower(fgetc(fl));
count += (ch >= 'a' && ch <= 'z') ? 1 : 0;
}
fclose(fl);
printf("Number of Alphabets in the file \" %s \"-> \t %d \n", fin, count);
}
int main()
{
countVowel("mno"); // output -> 10
countConsonant("mno"); // output -> 0
countAlphabet("mno"); // output -> 0
return 0;
}
Here are the contents of "mno" file ->
qwertyuiopasdfghjklzxcvbnm, QWERTYUIOPASDFGHJKLZXCVBNM, 1234567890
As others have mentioned, your handling of EOF was incorrect:
ch was uninitialized on the first loop iteration
Doing tolower(fgetc(fl)) would obliterate the EOF value.
Using char ch; instead of int ch; would allow a [legitimate] 0xFF to be seen as an EOF.
But, it seems wasteful to have three separate functions to create the three different counts because the most time is spent in the I/O versus the determination of what type of character we're looking at. This is particularly true when the counts are so interelated.
We can keep track of multiple types of counts easily using a struct.
Here's a refactored version that calculates all three counts in a single pass through the file:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
struct counts {
int vowels;
int consonants;
int alpha;
};
void
countAll(const char *fin,struct counts *count)
{
FILE *fl;
int ch;
int vowel;
count->vowels = 0;
count->consonants = 0;
count->alpha = 0;
fl = fopen(fin, "r");
if (fl == NULL) {
perror(fin);
exit(1);
}
while (1) {
ch = fgetc(fl);
// stop on EOF
if (ch == EOF)
break;
// we only care about alphabetic chars
if (! isalpha(ch))
continue;
// got one more ...
count->alpha += 1;
ch = tolower(ch);
// is current character a vowel?
vowel = (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u');
// since we know it's alphabetic, it _must_ be either a vowel or a
// consonant
if (vowel)
count->vowels += 1;
else
count->consonants += 1;
}
fclose(fl);
printf("In the file: \"%s\"\n",fin);
printf(" Number of Vowels: %d\n",count->vowels);
printf(" Number of Consonants: %d\n",count->consonants);
printf(" Number of Alphabetics: %d\n",count->alpha);
}
int
main(void)
{
struct counts count;
countAll("mno",&count);
return 0;
}
For your given input file, the program output is:
In the file: "mno"
Number of Vowels: 10
Number of Consonants: 42
Number of Alphabetics: 52
You are using ch uninitialized. at while (ch != EOF). Every function call after the first has ch equal to 0 at the start, because you forgot to initialize it and the memory was set to -1 before. You can fix it by replacing the loops like this:
int ch;
...
while ((ch = fgetc(fl)) != EOF)
{
ch = tolower(ch);
count += ...;
}
Here ch is getting initialized before you check it and later converted to lowercase.
EDIT:
Note that this only works if ch is an int, so it can handle the value of -1 (EOF) and the byte 255 is not truncated to -1.
EDIT:
At first I said ch was 0 all the time. It was -1. I am so sorry, I swapped it with the null terminator, which is usually the reason for such behavior.
char ch;
int nr=0;
printf("\n: ");
ch = getchar();
while(ch != 'q' && ch != 'Q'){
ch = tolower(ch);
if(ch == 'a' || ch == 'e' || ch == 'o' || ch == 'i' || ch == 'u')
nr++;
printf("something");
ch = getchar();
}
printf("vocale: %d", nr);
its supposed to count the number of vowels until the user presses q or Q. it's such a silly program and yet i cant get past it.
Instead of using getchar
ch = getchar();
that also reads white space characters use scanf like
scanf( " %c", &ch );
Pay attention to the leading space in the format string. It allows to skip white space characters.
For example
while ( scanf( " %c", &ch ) == 1 && ch != 'q' && ch != 'Q'){
Also it will be more safer to write
ch = tolower( ( unsigned char )ch );
The problem is, that the input only gets flushed to your program whenever the user presses enter. Another reason why it seems not to work is, because you don't have a newline at the end of you output (printf("vocale: %d", nr); ), which causes the output not to be flushed to the terminal when the program ends. Fix this and your program works, but maybe not as you expect it to, because you still have to press enter. It will still only count to the first 'q' found.
int main() {
char ch;
int nr = 0;
printf(": ");
while(tolower(ch = getchar()) != 'q'){
ch = tolower(ch);
if(ch == 'a' || ch == 'e' || ch == 'o' || ch == 'i' || ch == 'u')
nr++;
}
printf("vocale: %d\n", nr);
}
The program:
: aeu q oi (here I pressed enter)
vocale: 3
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);
}
}
I am trying to take in 10 characters over a serial console and add them to an array called buffer. The first character needs to be 'L' or 'S' and the next characters either '1' or '0'.
The code passes the first if statement ok. But the line if((buffer[0] != 'L') || (buffer[0] != 'S')) doesn't seem to work even when I enter 'L' OR 'S'.
Is there anything wrong with using the buffer[0] != notation?
int main(void)
{
char ch;
char buffer[10] = "";
putstring("Enter 9 characters beginning with 'L' or 'S' and 8 digits\r\n");
for (int i = 0; i < 9; i++) {
ch = getcharacter();
if ((ch == '0') || (ch == '1') || (ch == 'L') || (ch == 'S')) {
buffer[i] = ch;
//check first character
if((buffer[0] != 'L') || (buffer[0] != 'S')) {
printf("First letter must be L or S\r\n");
goto error;
}
error:
return -1;
}
}
}
int getcharacter(void) {
char c = 0;
const uint32_t recieve_ready = 1 << 7;
//disable interrupt for a read ready
*uart_control_reg = 0;
while (1) {
//check if RRDY bit is set
if ((*uart_status_reg) & recieve_ready) {
c = *uart_rxdata_reg;
break;
}
}
return ((char) c);
}
if((buffer[0] != 'L') || (buffer[0] != 'S'))
is wrong, you need
if((buffer[0] != 'L') && (buffer[0] != 'S'))
or
if (!(buffer[0] == 'L' || buffer[0] == 'S'))
Your original code was "if the char is not L or the char is not S" which is always true. If the char is L, then the second part was true, making the whole if statement true.
Just noticed Chris Turner's comment above. The return -1 is always executed, move it to replace the line that says goto error.
Try using
if((buffer[0] != 'L') && (buffer[0] != 'S'))
instead of
if((buffer[0] != 'L') || (buffer[0] != 'S'))
Just some logic problem here. According to your code, the char needs to be equal to 'L' AND 'S' to avoid the condition, which is never the case !
Write a program that reads input up to # and reports the number of times that the sequence ei occurs.
I have little confusion with sequence such as 'ieei' where compiler does enter 3rd 'e' but never fetches 'i' with getchar(), why and if someone can improve this before myself it'd be good?
char ch;
int sq=0;
while ((ch = getchar()) != '#')
{
if (ch == 'e')
{
ch = getchar();
if (ch == 'e')
ch = getchar();
if (ch == 'i')
sq++;
}
}
printf("Sequence occurs %d %s\n", sq, sq == 1 ? "time" : "times");
In my opinion it's simplest to keep the result of the last getchar() in a variable rather than have an extra getchar() inside your loop.
char ch;
int sq=0;
char lastCh = ' ';
while((ch=getChar())!='#') {
if(lastCh=='e' && ch=='i')
sq++;
lastCh=ch;
}
This gives the correct result no matter how many e's in a row or whatever, and breaks at the first # character.
I'm tempted to implement it as:
char ch=0;
int sq=0;
do{
if( (ch=( ch=='e'? ch:getchar() )) == 'e' && (ch=getchar()) == 'i' )
++sq;
}while(ch!='#');
But it uses ?: and && for control flow, which might be confusing especially to beginners.
On second thought it's not that hard to unroll it:
char ch=0;
int sq=0;
do{
if( ch!='e' ) ch = getchar();
if( ch == 'e' ){
ch = getchar();
if( ch == 'i' ) ++sq;
}
}while(ch!='#');