So, I'm just learning how to code in C and I'm a bit stumped by what my teacher is asking. Basically, we need to create a program that reads characters from two separate files character by character and if the two characters are the exact same it is to be printed to a third file. Normally, I would use an array to do this but, we have specifically been told that we are not allowed to use an array. I sort of have it working in that it prints characters to the third file but it prints numbers and punctuation in addition to characters. Obviously, I'm missing something but I don't know what it is. Here is my code:
int main(int argc, char *argv[]) {
FILE *fp, *fp2, *ofp;
char a, b;
fp = fopen("input1a.txt", "r");
fp2 = fopen("input1b.txt", "r");
ofp = fopen("output.txt", "w");
while((a=getc(fp))!= -1){
b=getc(fp2);
if(isalpha(a) == isalpha(b)){
putc(a, ofp);
letters++;
}
}
return 0;
}
From what I have read, isalpha should check to see if the character is an alphabetical character but, in this instance is there something better for me to use? Thanks for any help you can give me!
This is the problem
if(isalpha(a) == isalpha(b)) {
it sould be
if (isalpha(a) && isalpha(b) && a == b)
You are not comparing whether the characters are equal, but instead you are comparing if both are alphabetic or not, in case they are both alphabetic or they are both NOT alphabetic the character will be printed to the file.
Also, get used to writing safe code which is also clean and readable, like the following (note that there are elegant methods to handle errors, and you can add error messages):
int main(int argc, char *argv[])
{
FILE *in[2];
FILE *out;
int chars[2]; // getc() returns `int' not `char'
int counter;
in[0] = fopen("input1a.txt", "r");
if (in[0] == NULL)
return -1;
in[1] = fopen("input1b.txt", "r");
if (in[1] == NULL) {
fclose(in[0]);
return -1;
}
output = fopen("output.txt", "w");
if (output == NULL) {
fclose(in[0]);
fclose(in[1]);
return -1;
}
counter = 0;
while (((chars[0] = getc(in[0])) != EOF) && ((chars[1] = getc(in[1])) != EOF) {
if (chars[0] == chars[1] && isalpha(chars[0])) {
putc(chars[0], out);
counter++;
}
}
// Release ALL resources, it's a good habit
fclose(inputs[0]);
fclose(inputs[1]);
fclose(output);
// Not required but a good habit too
return 0;
}
Don't use magic numbers, EOF is normally -1 but it's better to use EOF to make the code readable and robust.
Related
I am trying to count the number of lines and characters whatever they may be in a file that I specify from argv. But I get a segmentation fault when I hit the while loop for some reason. The program runs fine without the while loop, though it only goes through once.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
if(argc != 2) {
return 0;
}
FILE *fp;
char c;
int lines = 0;
int chs = 0;
fp = fopen(argv[1], "r");
//Segmentation Fault happens here on the while loop
while((c = fgetc(fp)) != EOF) {
if(c == '\n') {
lines += 1;
}
else {
chs += 1;
}
}
printf("Charaters: %d\n", chs);
printf("lines: %d\n", lines);
if(fp){
fclose(fp);
}
return 0;
}
Your code needs to be follow Idiomatic C more closely.
You should validate fopen immediately, instead of after you've already attempted to use fp.
fgetc returns int, not char. This is because it needs to return side-channel information about the status of the stream (i.e. EOF), this information cannot be represented by char, but you can safely cast the int value to char if the value is not EOF.
Your code treats \r as a regular character when it is commonplace for \r\n to represent a line-break (not just a solitary \n), you might want to consider how you handle different character classes.
Your program does not handle non-trivial encodings (i.e. it will only correctly handle files in your system's native encoding, presumably ASCII). You should use a Unicode library to correctly read individual characters from a file: for example your program will treat a surrogate-pair in UTF-8 as two characters instead of 1, and would incorrectly count UTF-16 files.
Better:
FILE* fp = fopen( argv[1], "r" );
if( !fp ) {
printf( "Could not open file \"%s\" for reading.\r\n", argv[1] );
return 1;
}
int lines = 0;
int chars = 0;
int nc;
while( ( nc = fgetc( fp ) ) != EOF ) {
char c = (char)nc;
if ( c == '\n' ) lines++;
else if( c != '\r' ) chars++;
}
printf( "Characters: %d\r\nLines: %d\r\n", chars, lines );
fclose( fp );
return 0;
So I've tried searching for a solution to this extensively but can only really find posts where the new line or null byte is missing from one of the strings. I'm fairly sure that's not the case here.
I am using the following function to compare a word to a file containing a list of words with one word on each line (dictionary in the function). Here is the code:
int isWord(char * word,char * dictionary){
FILE *fp;
fp = fopen(dictionary,"r");
if(fp == NULL){
printf("error: dictionary cannot be opened\n");
return 0;
}
if(strlen(word)>17){
printf("error: word cannot be >16 characters\n");
return 0;
}
char longWord[18];
strcpy(longWord,word);
strcat(longWord,"\n");
char readValue[50] = "a\n";
while (fgets(readValue,50,fp) != NULL && strcmp(readValue,longWord) != 0){
printf("r:%sw:%s%d\n",readValue,longWord,strcmp(longWord,readValue));//this line is in for debugging
}
if(strcmp(readValue,longWord) == 0){
return 1;
}
else{
return 0;
}
}
The code compiles with no errors and the function reads the dictionary file fine and will print the list of words as they appear in there. The issue I am having is that even when the two strings are identical, strcmp is not returning 0 and so the function will return false for any input.
eg I get:
r:zymoscope
w:zymoscope
-3
Any ideas? I feel like I must be missing something obvious but have been unable to find anything in my searches.
I see you are appending a newline to your test strings to try to deal with the problem of fgets() retaining the line endings. Much better to fix this at source. You can strip all trailing stuff like this, immediately after reading from file.
readValue [ strcspn(readValue, "\r\n") ] = '\0'; // remove trailing newline etc
The string you are reading contains trailing character(s), and hence is not the same as the string you are comparing it against.
Remove the trailing newline (and CR if that is there); then you do not need to add any newline or carriage return to the string being compared:
int isWord(char *word, char *dictionary){
FILE *fp;
fp = fopen(dictionary, "r");
if (fp == NULL){
fprintf(stderr, "error: dictionary cannot be opened\n");
return 0;
}
if (strlen(word) > 16){
fprintf(stderr, "error: word cannot be >16 characters\n");
return 0;
}
char readValue[50];
while (fgets(readValue, 50, fp) != NULL){
char *ep = &readValue[strlen(readValue)-1];
while (*ep == '\n' || *ep == '\r'){
*ep-- = '\0';
}
if (strcmp(readValue, word) == 0){
return 1;
}
}
return 0;
}
I'm fairly new to C and i've been stuck on this problem for a few hours now. Basically I'm trying to develop a program that takes a character and zero of more file names as command-line arguments. If no arguments follow the characters, have the program read the standard input. else, have it open each file in turn and report how many times the character appears in each file to an output file. Here's my code and i'm not very sure if my whole logic is correct for this program. Here's my code so far:
int main(int argc, char *argv[]){
FILE *in = stdin;
FILE *out = stdout;
//FILE *hold;
int j,c, count[NUM] ={0}, total =0;
for(j=1;j<argc;j++){
if(argv[j][0] == '-'){
if(argv[j][1] == 'o'){
if(argv[j][2] == '\0')
out = fopen(argv[j++],"w");
else
out = fopen((argv[j] +2),"w");
}
} else {
in = fopen(argv[j],"r");
}
while((c = fgetc(in)) != EOF){
count[c]++;
total++;
}
if(fclose(in) != 0)
fprintf(stderr,"error in closing file %s\n", argv[1]);
getchar();
return 0;}
I did solve a few other command line argument practices with no problems but this one seems to be a bit harder for my current level in C. Thank you for your help
The code is supposed to read a user-inputted text file name, copy every character into a multidimensional array, then display it with standard output. It compiles, but produces unintelligible text. Am I missing something?
for (i = 0; i < BIGGEST; i++) {
for (j = 0; j < BIGGESTL; j++) {
if (fgetc(array, fp) ) != EOF)
array[i][j] = c;
else array[i][j] = '\0'
}
fclose(fp);
return 0;
}
You stop filling the array when you encounter EOF, but you print the full array out no matter what.
If the data read from the file is smaller than the input array, you will read that data in and then print that data out, plus whatever random characters were in the memory locations that you do not overwrite with data from the file.
Since the requirement seems to be to print text data, you could insert a special marker in the array (e.g. '\0') to indicate the position where you encountered EOF, and stop displaying data when you reach that marker.
You had better read each line from file
For example:
int i = 0;
while(fgets(text[i],1000,fp))
{
i++;
}
Though the question is edited and only part of the code is left in question. I am posting more than what is required for the question at the moment.
Reason being, there can be numberous improvements to originally posted full code.
In main() function:
You need to check for the argc value to be equal to 2 for your purpose and only then read in value of argv[1] . Else if program executed without the command-line-argument which is file_name in this case, invalid memory read occurs, resulting in segmentation fault if you read in argv[1].
In read_file_and_show_the contents() function:
Stop reading file if end of file is reached or maximum characters is read and store in the character array.
Below Program will help you visualize:
#include <stdio.h>
/*Max number of characters to be read/write from file*/
#define MAX_CHAR_FOR_FILE_OPERATION 1000000
int read_and_show_the_file(char *filename)
{
FILE *fp;
char text[MAX_CHAR_FOR_FILE_OPERATION];
int i;
fp = fopen(filename, "r");
if(fp == NULL)
{
printf("File Pointer is invalid\n");
return -1;
}
//Ensure array write starts from beginning
i = 0;
//Read over file contents until either EOF is reached or maximum characters is read and store in character array
while( (fgets(&text[i++],sizeof(char)+1,fp) != NULL) && (i<MAX_CHAR_FOR_FILE_OPERATION) ) ;
//Ensure array read starts from beginning
i = 0;
while((text[i] != '\0') && (i<MAX_CHAR_FOR_FILE_OPERATION) )
{
printf("%c",text[i++]);
}
fclose(fp);
return 0;
}
int main(int argc, char *argv[])
{
if(argc != 2)
{
printf("Execute the program along with file name to be read and printed. \n\
\rFormat : \"%s <file-name>\"\n",argv[0]);
return -1;
}
char *filename = argv[1];
if( (read_and_show_the_file(filename)) == 0)
{
printf("File Read and Print to stdout is successful\n");
}
return 0;
}
I use below code to read a char from file and replace it with another,
but I have an error.loop in going to end of file.
What is wrong?
I tested this code on linux (netbeans IDE) and it was correct and worked beautiful but when I tried to use VS 2008 in windows , I found a non end loop.
//address = test.txt
FILE *fp;
fp=fopen(address,"r+");
if(fp == 0)
{
printf("can not find!!");
}
else
{
char w = '0'; /// EDIT : int w;
while(1)
{
if((w = fgetc(fp)) != EOF)
{
if((w = fgetc(fp)) != EOF)
{
fseek(fp,-2,SEEK_CUR);
fprintf(fp,"0");
}
}
else
{
break;
}
}
}
fclose(fp);
You are storing the result of fgetc in a char, instead of an int.
char w = '0'; /* Wrong, should be int. */
Incidentally, this problem is mentioned in the C FAQ.
If type char is unsigned, an actual
EOF value will be truncated (by having
its higher-order bits discarded,
probably resulting in 255 or 0xff) and
will not be recognized as EOF,
resulting in effectively infinite
input.
EDIT
Reading your question again, it's highly fishy the way you seek back two characters and write one character. That could well lead to an infinite loop.
EDIT2
You (likely) want something like this (untested):
while ((w = getc(fp)) != EOF) {
fseek(fp, -1, SEEK_CUR);
fprintf(fp, "0");
fflush(fp); /* Apparently necessary, see the answer of David Grayson. */
}
The fopen documentation on cplusplus.com says:
For the modes where both read and
writing (or appending) are allowed
(those which include a "+" sign), the
stream should be flushed (fflush) or
repositioned (fseek, fsetpos, rewind)
between either a reading operation
followed by a writing operation or a
writing operation followed by a
reading operation.
We can add an fflush call after the fprintf to satisfy that requirement.
Here is my working code. It creates a file named example.txt and after the program exits that file's contents will be 000000000000n.
#include <stdio.h>
int main(int argc, char **argv)
{
FILE * fp;
int w;
fp = fopen("example.txt","w");
fprintf(fp, "David Grayson");
fclose(fp);
fp = fopen("example.txt","r+");
while(1)
{
if((w = fgetc(fp)) != EOF)
{
if((w = fgetc(fp)) != EOF)
{
fseek(fp,-2,SEEK_CUR);
fprintf(fp,"0");
fflush(fp); // Necessary!
}
}
else
{
break;
}
}
fclose(fp);
}
This was tested with MinGW in Windows.