Reading and checking a file's content in C - c

So I am writing a program in C that takes in a few command-line arguments and also reads a file and prints it to standard out. This is my code thus far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main( int argc, char* argv[] ) {
char* file_path;
float a;
float b;
char filedata[200];
if (argc != 4) {
printf("Error: 4 arguments are required.\n");
return -1;
}
file_path = argv[1];
a = atof(argv[2]);
b = atof(argv[3]);
if( a == 0.0 ) {
printf("Error: bad float arg\n");
return -1;
}
if( b == 0.0 ) {
printf("Error: bad float arg\n");
return -1;
}
FILE* fp = fopen( file_path, "r");
if( fp == NULL ){
printf( "Error: bad file; %s\n", file_path);
return -1;
}
while( fgets( filedata, 200, fp ) ){
printf("%s", filedata);
}
fclose(fp);
}
At the very bottom I have began to read a file. What I am trying to do is find files that contain the characters "#A#" and "#B#" and then print an error message when files containing these characters are not present.
Unfortunately, a simple if statement will not work in this scenario as I am not checking for equality but rather whether or not something is present.
If anybody could tell me about any C functions that are able to read and check the contents of a file, along with a few more specifics, then I would highly appreciate it!

After taking each line (into 'filedata') simply use the strstr function to check if it contains that substring "#A#" etc.
if strstr finds the substring it will return a pointer to it, otherwise it will return a NULL pointer.
So you should write something like this:
if ( strstr(filedata, "#A#") == NULL )
printf("Error\n");
but since you are looking at the entire file for this substring, you need to check all the lines before you conclude that there is an error.

Related

Segmentation Fault on my while loop

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;

Command line error

The following code is supposed to read a text file character by character and count the frequency of their occurrence. However, on the Linux command line, it compiles and when I try to run it by the command ./program<file.txt it shows
useage: huffman <filename>
I don't know what's the error.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int count[26];
int main(int argc, char ** argv)
{
unsigned char c;
FILE * file;
int i;
if ( argc != 2 ) {
fprintf(stderr, "Useage: huffman <filename>\n");
exit(1); // exit with error code
}
file = fopen(argv[1], "r");
assert( file != NULL );
c = fgetc(file);
while( !feof(file) ) {
c = fgetc(file);
count[c-'a']++;
}
for(i=0; i<26; i++)
printf("count[%c]=%d\n",65+i,count[i]);
fclose(file);
return 0;
As you execute it as
$ ./program < file.txt
you are calling the program with zero arguments and set its standard input stream to read from file.txt. Therefore, argc in your main is 1 and you get the error message you have placed for this case.
To solve this, you can either
run the program as it's supposed to (without shell redirection)
$ ./program file.txt
or modify your program such that it reads from standard input if called with no arguments. It may then be called either way.
Many POSIX commands use the convention that if called with no file names, they read from standard input instead. For example,
$ cat file.txt
outputs the contents of file.txt while
$ cat
parrots back at you everything you type.
To implement this, you'd need something like this.
FILE * file = NULL;
if (argc == 1)
{
file = stdin;
}
else if (argc == 2)
{
file = fopen(argv[1], "r");
if (file == NULL)
{
fprintf(stderr, "error: %s: %s: %s\n",
"cannot read file", argv[1], strerror(errno));
return EXIT_FAILURE;
}
}
else
{
fprintf(stderr, "error: %s\n", "too many arguments");
return EXIT_FAILURE;
}
assert(file != NULL); /* we have made this sure */
c must be an int.
Make sure c is in proper range before indexing the array.
c = fgetc(file);
if (islower((unsigned char)c)) count[c-'a']++; // assumes 'a' thru 'z' are sequential
You need to #include <ctype.h> for the correct prototype for islower()

hexadecimal to decimal conversion

The first piece of code prints each line in b.txt in a new line when it outputs it, and the second code is the conversion from hexadecimal to decimal. I am bad at writing big programs, so I split the task and write smaller programs instead. I am having trouble combining these two programs. Can anyone help ?
#include <stdio.h>
int main ( int argc, char **argv )
{
FILE *fp = fopen ( "b", "r");
char line[1024];
int ch = getc ( fp );
int index = 0;
while ( ch != EOF ) {
if ( ch != '\n'){
line[index++] = ch;
}else {
line[index] = '\0';
index = 0;
printf ( "%d\n", line );
}
ch = getc ( fp );
}
fclose ( fp );
return 0;
}
This is the second program
#include <stdio.h>
#include <stdlib.h>
int main()
{
unsigned int d;
FILE *fp;
FILE *ptr_file;
fp = fopen("normal_data","r"); // read mode
ptr_file =fopen("normal_decimal", "w");
while(fscanf(fp,"%x", &d) == 1)
{
fprintf(ptr_file, "%d /n", d);
}
while( ( d = fgetc(fp) ) != EOF )
fclose(fp);
return 0;
}
It is good programming practice to split your program in small related fragments.
But instead of using a main function everywhere , try making functions which accomplish certain tasks and add them to a header file.
This will make it much easier to write, debug and re-use the code.
In the above case, converting hexadecimal to decimal is clearly something which maybe used again and again.
So, just make a function int hex_to_dec(char* input); which takes a string of input e.g,"3b8c" and converts it to a decimal and returns the converted value.
You may also want to make function void printFile(FILE* fp); which takes the pointer to a file and prints it data to stdout.
You can add these and other functions you have made, to a header file like myFunctions.h and then include the file into whatever program you need to use your functions in.

Segmentation Fault when using fopen on argv

I continue to have a segmentation fault when I try and execute the following code...
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
if (argc < 4){
fprintf (stderr,"usage message");
return (1);
}
FILE *src = fopen(argv[1],"r"); //file pointer to inputFile
FILE *outputFile = fopen(argv[2],"w"); //file pointer to outputFile
int nth = atoi(argv[3]); //nth term value
printf("nth term is %d",nth);
int c;
int currNum;
int currCount = 1;
c = fscanf(src, "%d\n",currNum); //read ints line by line
while( c == 1 ){
fscanf(src,"%d\n",currNum);
++currCount;
if (currCount % nth == 0){
fprintf (outputFile, "%d\n", currNum);
}
}
}
I'm not sure if I have to somehow convert argv[1] and argv[2] before I can use them as the file names.
Did you provide a command line argument? You should check that by using an if statement before opening the files. For example, you could add
if ( argc < 4 )
{
printf ( stderr, "usage message\n" );
return ( 1 );
}
Also, change that stoi for argv[3] to atoi.
You don't need to add \n for fscanf. Just "%d" will do fine.
giving input parameters to "fscanf" is wrong. check below one.......
c = fscanf(src, "%d\n",currNum); // wrong
c = fscanf(src, "%d\n",&currNum);
fscanf(src,"%d\n",&currNum);
You can use atoi to convert to int
int nth = atoi( argv[3] );
You also can NULL check file* src and outfile. If you are not giving correct paths then fopen may fail.

Replace string with another

I am just not sure why my replaceWord isn't going in to the file at all i have used all the commented out and so on and so forth. I am just trying to replace with with the text received from the command line argument. I know i might be far off I was just looking for a relatively easy way to do it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main ( int argc, char *argv[] )
{
if ( argc != 4 ) /* argc should be 2 for correct execution */
{
/* We print argv[0] assuming it is the program name */
printf( "usage: %s filename\n", argv[0] );
}
else
{
// We assume argv[1] is a filename to open
char* wordReplace = argv[1];
char* replaceWord = argv[2];
FILE *file = fopen( argv[3], "r" );
/* fopen returns 0, the NULL pointer, on failure */
if ( file == 0 )
{
printf( "Could not open file\n" );
}
else
{
char string[100];
int len = 0;
/* read one character at a time from file, stopping at EOF, which
indicates the end of the file. Note that the idiom of "assign
to a variable, check the value" used below works because
the assignment statement evaluates to the value assigned. */
while ( (fscanf( file, "%s", string ) ) != EOF )
{
len = strlen(string);
printf( "%s\n", string );
if(strcmp(string, wordReplace) == 0){
//fseek (file, (-strlen(string) + 1), 1);
//fputc(*replaceWord,file);
//replaceWord++;
//strcpy(string, replaceWord);
fprintf(file,"%s",replaceWord);
fputs(replaceWord, file);
printf("\n%d\n", len);
}
}
fclose( file );
}
}
printf("\n");
return 0;
}
You've opened the file in r ie read mode and trying to write to it.
Also after correcting that, note that, the replaced word and word to be replaced have to be of the same size, if you want to replace the file in place. Else you will end up overwriting other data. And you need to use functions like fseek to reposition the internal file pointer as fp would have moved ahead after fscanf

Resources