#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main ( int argc, char *argv[] )
{
if ( argc != 4 ) /* argc should be 4 for correct execution */
{
/* 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;int count = 0;int i = 0;int k = 0;
while ( (fscanf( file, "%s", string ) ) != EOF )
{
len = strlen(string);
count++;
char charray[len+1];
if(count == 1)
{
for (i = 0; i < len; i++)
{
charray[i] = replaceWord[i];
printf("%c\n", charray[i]);
}
}
//printf("%c\n", charray[0]);
printf( "%s\n", string );
if(strcmp(string, wordReplace) == 0)
{
for(k = 0; k < strlen(replaceWord); k++)
{
fseek (file, (-(long)len), SEEK_CUR);
fputc(charray[k],file);
//replaceWord++;
}
//strcpy(string, replaceWord);
//fprintf(file,"%s",replaceWord);
//fputs(string, file);
//printf("\n%d\n", len);
}
}
fclose( file );
}
}
printf("\n");
return 0;
}
This code currently works in replacing the First word properly, but if there are multiple words that i want overwritten with the replace word or the word appears somewhere else in the text it will not properly change it, and it will change it to ram trash etc. I was curious if anyone could lead me to a reason why thank you.
Assuming the words are the same length (if not you have quite a few more issues):
Let's say you have a 4 character word:
fseek (file, (-(long)len), SEEK_CUR); will go back to position 0 (4-4), fputc(charray[k],file); will update to position 1, then you back 4 more which is an error but since you're not checking the return value from fseek you will not know this. At this point the algorithm is not working any more since your assumed file positions are all wrong
EDIT:
if(strcmp(string, wordReplace) == 0)
{
fseek (file, (-(long)len), SEEK_CUR);
for(k = 0; k < strlen(replaceWord); k++)
{
fputc(charray[k],file);
}
}
fflush(file); //you need to flush the file since you are switching from write to read
EDIT 2: reason for flush: from 4.5.9.2 ANSI C, similar paragraph in C99 7.19.5.3):
When a file is opened with update mode ('+' as the second or third character in the mode argument), both input and output may be performed on the associated stream. However, output may not be directly followed by input without an intervening call to the fflush function or to a file positioning function ( fseek , fsetpos , or rewind ), and input may not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file.
Between the read and write you have the fseek already so that is not a problem
Related
I want to parse a .txt file into a 1D array in C. I'm using the fgets function to read the contents of the file into the array("waveform" as the array into which the file contents are to be stored - defined as a "char"). The saved values need to be saved into a new array as integer values. I am not sure where I am going wrong.
P.S: I am new to programming in C, please bear with me :)
Please ignore the indexing issues, done due to pasting
int main(){
int a, win[10];
FILE *filename = fopen("testFile.txt","r");
char waveform[10];
if (filename == NULL)
{
printf("Error opening file.\n");
exit(8);
}
for(int i =0;1;i++){
if(fgets(waveform[i], 10, filename) == NULL);
break;
if(i < 10)
{
a = atoi(waveform[i]);
win[i] = a;
}
}
fclose(filename);
return 0;
}
Compiler errors - image embedded
Data in testFile.txt:
1 to 10 in a row vector.
You are on the right track. Here is my contribution on the topic:
Open the file (fopen)
Count number of lines (getc and rewind)
Read all lines into array (getline)
Free memory and close file (free and fclose)
Code example:
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
// Open File
const char fname[] = "testFile.txt";
FILE *fp = fopen(fname, "r");
if( !fp )
goto error_open_file;
printf("Opened file: %s\n", fname);
// Count Lines
char cr;
size_t lines = 0;
while( cr != EOF ) {
if ( cr == '\n' ) {
lines++;
}
cr = getc(fp);
}
printf("Number of lines: %ld\n", lines);
rewind(fp);
// Read data
{// 'goto' + data[lines] causes error, introduce block as a workaround
char *data[lines];
size_t n;
for (size_t i = 0; i < lines; i++) {
data[i] = NULL;
size_t n = 0;
getline(&data[i], &n, fp);
if ( ferror( fp ) )
goto error_read_file;
}
for (size_t i = 0; i < lines; i++) {
printf("%s", data[i]);
free(data[i]);
}
}
// Close File
fclose(fp);
return 0;
error_read_file:
perror("fopen ");
return 1;
error_open_file:
perror("getline ");
return 2;
}
There are several errors in this loop
for(int i =0;1;i++){
if(fgets(waveform[i], 10, filename) == NULL);
break;
if(i < 10)
{
a = atoi(waveform[i]);
win[i] = a;
}
}
For starters there is a semicolon after the if statement
if(fgets(waveform[i], 10, filename) == NULL);
^^^
Secondly the fgets call
fgets(waveform[i], 10, filename)
^^^
is invalid because the type of the expression waveform[i] is char.
And correspondingly this statement
a = atoi(waveform[i]);
is also invalid.
There must be at least
fgets( waveform, 10, filename)
and
a = atoi( waveform );
I suppose that each line of the file contains exactly one number. (Otherwise you should use for example sscanf to extract numbers from a line using an internal additional loop.)
The loop can look like
int i = 0;
for ( ; i < 10 && fgets( waveform, 10, filename) != NULL; i++ )
{
a = atoi( waveform );
win[i] = a;
}
After the loop the variable i will contain the actual number of elements of the array win.
Pay attention to that the name filename is not good for a pointer of the type FILE *. File name is the string "testFile.txt" in your code.
If you want to use the fgets() function you don't have to put it into a loop. Indeed, the second argument of fgets() is the number of elements you want to read.
I would have put the fgets() into a singl-line instruction, and then loop from 0 to 10 to make the conversion from char to int with the atoi() function.
Moreover, you have a ; at the end of your if() statement, so you'll execute it not in the way you want.
I'm having some problems with this little function that can read a file:
void ReadFile(char *name) {
FILE *fr;
int lenght, i;
fr = fopen(name, "r"); //Open the file reader
fseek(fr, 0, 2); //Set the pointer at the EOF
lenght = ftell(fr); //Read the ending position
printf("\nDEBUG lenght:%d\n", lenght);
fseek(fr, 0, 0); //Return at the beginning of the file
printf("File read:\n\n");
for (i = 1; i <= lenght; i++) {
printf("%c", getc(fr));
fseek(fr, i, 0);
}
fclose(fr);
}
This is the file that it reads:
qwerty
asdfgh
zxcvbn
But this is the output of the program:
DEBUG lenght:24
File read:
qwerty
asdfgh
zxcvbn
It is basically reading an extra "\n" when there is one before.
Any ideas of why the code doesn't work?
Thanks
If you open a file in text mode (as you do), then a call to fseek may only contain offset values that have been previously retrieved by an ftell function (cf, for example, cppreference/fseek):
If the stream is open in text mode, the only supported values for
offset are zero (which works with any origin) and a value returned by
an earlier call to ftell on a stream associated with the same file
(which only works with origin of SEEK_SET).
In your for-loop, however, you are passing the value of i, which is not retrieved by ftell.
Besides that, your fseek in the loop is superflous, as fgetc moves the read pointer forward anyway. So for (i = 1; i <= lenght; i++) { printf("%c", getc(fr)); } should do the job.
the following proposed code:
cleanly compiles
performs the desired functionality
properly checks for errors
and now, the proposed code:
#include <stdio.h> // EOF, fopen(), getc(), putc() fclose() puts() perror()
#include <stdlib.h> // exit(), EXIT_FAILURE
// prototype
void ReadFile(char *filename);
void ReadFile(char *filename)
{
FILE *fp = fopen( filename, "r" );
if( !fp )
{
perror( "fopen failed" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
puts("File read:\n");
int ch;
while( (ch = getc( fp )) != EOF )
{
putchar( ch );
}
fclose(fp);
}
Here is my code that is doing the printing that gets messed up. The output is fine when you display it to your screen (terminal). Unfortunately when you redirect it to a text file it gets messed up. It displays the null characters (^#) and Enquiry characters (^E). I have to use a for loop like this or my outputs gets messed up. I can't use the %s option or my output won't be in the way I need it.
FILE *input;
char line[80] = {0};
while(fgets(line, 80, input) != NULL)
{
if((int)line[0] == 46)
{
//printf("You have a period \n");
for(i = 31; i < 80; i++)
{
printf("%c", line[i]);
}
//printf(" ------------------------\n");
memset(line, 0, 80);
comment_flag = 1;
}
}
This is what I mean when I say redirect.
gcc *.c
./a.out > text_file
#include <ctype.h>
and try
if (isprint((unsigned char)line[i]) || isspace((unsigned char)line[i]))
printf("%c", line[i]);
The condition in my condition only keeps printable characters (the isprint()) and space characters ('\n', '\t', ...). Other characters ('\0', '\x05', ...) are simply ignored for output. – pmg
its probably silly, but if in your file, you see your null/empty array positions to be displayed with a special character (^#), then all you have to do is to initialize your array with empty spaces, or better with '\0'.
You can do that even one time in the top of your programm, and if it doesn't work, try do that every time in the while loop, after printing the line into the file you want.
while(fgets(line, 80, input) != NULL)
{
//Your code here
for(i=0; i<80; i++)
line[i]='\0';
}
Just remove the "memset" function and try this.
if you just want to replace your output from screen to file, you just have to do this
#include <stdio.h>
int main ( void )
{
int i;
FILE *file = fopen ( "test.txt", "r" );
FILE *out = fopen ( "output.txt", "w");
if ( file != NULL )
{
char line [ 128 ]; /* or other suitable maximum line size */
while ( fgets ( line, sizeof line, file ) != NULL ) /* read a line */
{
if((int)line[0] == 46)
{
//printf("You have a period \n");
for(i = 31; i < 80; i++)
{
fputs(line,out);
}
}
}
fclose ( file );
fclose ( out );
}
return 0;
}
this writes to file properly, without any special characters displayed, and to your screen too, if you replace fputs, with printf, just like your answer in the top. If i got it right, that's what you want.
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 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