I am recently trying to write a code in which the program will show the derivative of a function using the product rule. The function can be either one of: x^n, sin(a*x) or cos(a*x). As an example it can be a set of three functions, so the file may look like this:
x^7*sin(3.14*x)
cos(4*x)*sin(5.2*x)
cos(2*x)*cos(8*x)
I wrote some local functions, such as
void derivcc ()
{
double a, b;
fscanf(f,"cos(%lf*x)*cos(%lf*x)",&a, &b);
if (a<0 && b<0)
printf("%lfsin(%lf*x)*cos(%lf*x)+%lfsin(%lf*x)*cos(%lf*x)\n",
-a,a,b,-b,b,a);
else if (a<0 && b>0)
printf("%lfsin(%lf*x)*cos(%lf*x)-%lfsin(%lf*x)*cos(%lf*x)\n",
-a,a,b,b,b,a);
else if (a>0 && b<0)
printf("-%lfsin(%lf*x)*cos(%lf*x)+%lfsin(%lf*x)*cos(%lf*x)\n",
a,a,b,-b,b,a);
else
printf("-%lfsin(%lf*x)*cos(%lf*x)-%lfsin(%lf*x)*cos(%lf*x)\n",
a,a,b,b,b,a);
}
However, the issue that I am having is in the main function. I want to know how should I address the while loop, so the local functions can work. Here is the main:
int main(void)
{
FILE * f;
char lines[50];
f=fopen("function.txt", "r");
if (f == NULL)
{
printf("Error with opening the file!/n");
exit (1);
}
int c;
fgets(lines, sizeof(lines), f);
char sin[]="sin";
char cos[]="cos";
char x[]="x^";
char *checkc, *checks, *checkx;
checkc = strstr(lines,cos);
checks = strstr(lines,sin);
checkx = strstr(lines, x);
double a,b;
while((c = getc(f)) != EOF)
{
if (checks == NULL)
{
if (checkc == NULL)
{
derivxx();
}
else
{
if (checkx==NULL)
derivcc();
else
{
if (lines[0] == cos[0])
derivcx();
else
derivxc();
}
}
}
else
{
if (checkc == NULL && checkx == NULL)
{
derivss();
}
else
{
if (checkc == NULL && checkx != NULL)/
{
if (lines[0]==sin[0])
derivsx();
else
derivxs();
}
else if (lines[0]==sin[0])
derivsc();
else
derivcs();
}
}
}
fclose(f);
}
You've got most of the code. You just need to rearrange it a little to make it work. Here's the code that you have:
int c;
fgets(lines, sizeof(lines), f);
char sin[]="sin";
char cos[]="cos";
char x[]="x^";
char *checkc, *checks, *checkx;
checkc = strstr(lines,cos);
checks = strstr(lines,sin);
checkx = strstr(lines, x);
double a,b;
while((c = getc(f)) != EOF)
{
}
The code reads the first line and then gets some information about that line using the strstr function. Then the while loop starts reading one character at a time.
What needs to happen is the while loop needs to read one line at a time. And the strstr calls need to be inside the while loop. So the code should look like this:
char sin[]="sin";
char cos[]="cos";
char x[]="x^";
char *checkc, *checks, *checkx;
double a,b;
while(fgets(lines, sizeof(lines), f) != NULL)
{
checkc = strstr(lines,cos);
checks = strstr(lines,sin);
checkx = strstr(lines, x);
}
Related
I have a function that returns the number of lines, characters, and words in an array. For some reason, when i loop through the array to print the values I am only getting the corrrect value for lines, the characters and words are returning as 0. All the functions are predetermined by my professor and my job is to fill them in.
int main(int argc, char **argv)
{
int *myArray = get_counts(argv[1]);
for (int i = 0; i < 3; i++)
{
printf("%d\n", myArray[i]);
}
return 0;
}
int *get_counts(char *filename)
{
FILE *file;
file = fopen(filename, "r");
if (file == NULL)
{
printf("NULL FILE");
}
char c;
int h;
bool whitespace = true;
static int arr[3] = {0,0,0};
do
{
c = fgetc(file);
if (c == '\n')
{
arr[0] ++;
}
}while (c != EOF);
while (true)
{
h = fgetc(file);
if (feof(file))
{
break;
}
else if (ferror(file))
{
printf("error reading file");
}
arr[2] ++;
if (whitespace && !isspace(h))
{
arr[1] ++;
whitespace = false;
}
else if (!whitespace &&isspace(h))
{
whitespace = true;
}
}
fclose(file);
return arr;
}
The best option is probably to just iterate through the file in one loop (you could also rewind() after the first loop). Use the return value of fgetc() to determine of you are at EOF instead of separate feof() calls. I also made the the result array an (out) argument instead of using a static variable (the latter is not reentrant if you ever want to call this from multiple threads and it's easy to do):
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
void get_counts(char *filename, int arr[3]) {
memset(arr, 0, 3 * sizeof(int));
FILE *file = fopen(filename, "r");
if (file == NULL) {
printf("NULL FILE");
return;
}
bool whitespace = true;
for(;;) {
int c = fgetc(file);
if(c == EOF)
break;
else if(c == '\n')
arr[0]++;
else if (whitespace && !isspace(c)) {
arr[1]++;
whitespace = false;
} else if (!whitespace && isspace(c))
whitespace = true;
arr[2]++;
}
fclose(file);
}
int main(int argc, char **argv) {
int myArray[3];
get_counts(argv[1], myArray);
for (int i = 0; i < 3; i++) {
printf("%d\n", myArray[i]);
}
}
The output on the above file is:
39
94
715
The word count 94 doesn't agree with wc -w but you could be using a different definition of what a word is.
It's a good idea to separate calculations and i/o, so consider opening and closing the file in main() and pass in the file handle. It becomes easy, for instance, to use the stdin file handle instead if you don't want to use a physical file.
After the first do-while loop the condition EOF occurs.
do
{
c = fgetc(file);
if (c == '\n')
{
arr[0] ++;
}
}while (c != EOF);
So the following while loop has no effect.
You should use only one loop to count lines, words and characters.
Pay attention to that the variable c should be declared as having the type int
int c;
Also you need to exit the function if the file was not opened.
whenever I run the program the second print statement isn't printing. I tried using a function but I'm new to C and don't really understand anything. I've also attached my activity as I'm not sure how to do the other things on it.activity photo
#include <stdio.h>
#include <string.h>
#define LINE_LENGTH 1000
int main(int argc, char **argv)
{
FILE *input_file = fopen("cstest.c", "r");
char line [LINE_LENGTH];
//while loop to ger
while (fgets(line, LINE_LENGTH, input_file) != NULL)
{
int ch = 0;//ch is the cast
int lines = 0;//start with one because
if (input_file == NULL)
return 0;
while (!feof(input_file))
{
ch = fgetc(input_file);
if (ch == '\n')
{
lines++;
}
}//end while
printf("lines: %d\n", lines);
}//end while loop
while (fgets(line, LINE_LENGTH, input_file) != NULL)
{
int ch = 0;//ch is the cast
int lines = 0;//start with one because
if (input_file == NULL)
return 0;
while (!feof(input_file))
{
int characters = 0;
char c;
for (c = getc(input_file); c != EOF; c = getc(input_file))
// Increment count for this character
characters = characters + 1;
printf("characters: %d\n", characters);
fclose(input_file);
}
}
}
I need to read a text file (E3-5.txt), and search for character c1 to be replaced by c2.
This is my incomplete code:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char c;
char c1 = 'm';
char c2 = 'a';
int i;
FILE* fp;
fp = fopen("C:\\E3-5.txt", "r+");
if (fp == NULL)
{
printf("File not found!");
return 0;
}
for(c = getc(fp); c != EOF; c = getc(fp))
{
if(c == 'm')
{
i = ftell(fp);
printf("\nPosition %d", i);
}
}
}
I am having trouble how to locate the position of c1 in the text and how to rewrite it.
Edit:
I used the code from the answer, but it didn't change the text.
This is the new code:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char c;
char c1 = 'm';
char c2 = 'a';
int i;
FILE* fp;
fp = fopen("C:\\E3-5.txt", "rb+");
if (fp == NULL)
{
printf("File not found!");
return 0;
}
else
{
for(c = getc(fp); c != EOF; c = fgetc(fp))
{
if(c == c1)
{
fseek(fp, -1, SEEK_CUR);
fputc(c2, fp);
}
else
{
return 0;
}
}
}
return 0;
}
The program returned 0 without writing anything in the text
Here you have a very naive one:
int freplace(FILE *f, char needle, char repl)
{
int result = 1;
int c;
if(f)
{
while((c = fgetc(f)) != EOF)
{
if(c == needle)
{
fseek(f, -1, SEEK_CUR);
fputc(repl, f);
//all I/O functions require error handling
}
}
}
return result;
}
getc() returns an int so you need to declare int c not char c to check for the EOF.
ftell() gets the location. Use fwrite() or fputc() to write to file at that location by setting with fseek().
Go to https://en.cppreference.com/w/c for reference. Lots of beginners fail to read all of the standard library functions, and some even reinvent the wheel.
You really don't want to directly manipulate a file. Ever. Doing so is just asking for data corruption. Instead, create a new file and move it when you're done. Also, it's a lot easier to write the code. You can do so with something like:
#include <stdio.h>
#include <unistd.h>
int
main(int argc, char **argv)
{
int c1 = argc > 1 ? argv[1][0] : 'm';
int c2 = argc > 2 ? argv[2][0] : 'a';
const char *path = argc > 3 ? argv[3] : "stdin";
FILE *in = argc > 3 ? fopen(path, "r") : stdin;
if( in == NULL ){
perror(path);
return 1;
}
FILE *out = stdout;
char tmp[1024] = ".tmpXXXXX";
char *outpath = "stdout";
if( argc > 3 ){
outpath = tmp;
int fd = mkstemp(tmp);
if( fd == -1 ){
perror("mkstemp");
return 1;
}
if( (out = fdopen(fd, "w")) == NULL ){
perror(tmp);
return 1;
}
}
int c;
while( (c = fgetc(in)) != EOF ){
if( c == c1 ){
c = c2;
}
if( fputc(c, out) == EOF ){
perror(outpath);
return 1;
}
}
if( argc > 3 ){
if( fclose(out) ){
perror(outpath);
return 1;
}
if( rename(outpath, path) ){
perror(path);
return 1;
}
}
return 0;
}
String replace
Just for completeness, here is a bit of code to replace a word in a file! This will replace a single character, so of course it answers the question and shows some useful examples.
This is also my first and only non-trivial golden program, written in May 1994! Although you can certainly find fault with it, it worked as intended and my co-workers and I used it many different ways for sysadmin-related tasks. Compiled on MS C/C++
#include <stdio.h>
#include <string.h>
#define err(e) {_fcloseall(); fprintf(stderr, \
"USAGE: chg source dest oldstr newstr\n%s\n",e); exit(1);}
main (int argc,char *argv[])
{
FILE *in,*out;
char buffer[200];
char *old,*new;
int i,j,k;
if (argc!=5)
err("invalid # of parameters");
if ((in=fopen(argv[1],"r"))==NULL)
err("Can't open source");
if ((out=fopen(argv[2],"w"))==NULL)
err("Can't open dest");
old=argv[3];
new=argv[4];
if (*old=='"')
old++;
if (*new=='"')
new++;
if (i=strlen(old) && old[i-1]=='"')
old[i-1]=0;
if (i=strlen(new) && new[i-1]=='"')
new[i-1]=0;
if (!*old)
err("Can't search for nothing!");
if (!*new)
err("Can't replace nothing!");
j=0;
while (!feof(in))
{
if ((buffer[j]=fgetc(in))==EOF)
break;
buffer[j+1]=0;
j++;
if (!old[j-1])
{
fprintf(out,new);
fputc(buffer[j-1],out);
j=0;
}
else if (_strnicmp(buffer,old,j))
{
fprintf(out,buffer);
j=0;
}
else if (j>195)
err("Internal error, buffer filled past 195");
}
}
I am working on a management system project and want to clear the file before adding data to it. I am using this code as a reference. I have rewritten the code from the reference and instead of writing the data from the temporary file(tmp) back to the original(FILE_NAME), I have printed it out to the terminal.
When I compile and run the program, it prints all the content and a few more lines after the end of the file. After this it stops and doesn't finish execution. I have added to comments to help understand my thought process better.
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#define BUFFER_SIZE 1000
#define FILE_NAME "data.csv"
int main()
{
FILE* file;
char buffer[BUFFER_SIZE];
// Opening file
if(file = fopen(FILE_NAME, "r+"))
{
char c; // To get character from buffer
int i = 0; // Index for the buffer character
int isEmpty = 1; // If the line is empty
FILE* tmp;
if(tmp = tmpfile())
{
while(1)
{
buffer[i++] = c;
if(c != '\n') // Checking for blank lines
{
isEmpty = 0;
}
else
{
if(c == '\n' && isEmpty == 0) // Read a word; Print to tmp file
{
buffer[i] = '\0';
fprintf(tmp, "%s", buffer);
i = 0;
isEmpty = 1;
}
else if(c == '\n' && isEmpty == 1) // NOT SURE WHY THIS IS IMPORTANT
{
buffer[i] = '\0';
i = 0;
isEmpty = 1;
}
}
if(c == EOF)
{ break; }
while(1) // Loop to print contents of tmp file onto terminal
{
c = getc(tmp);
printf("c: %c", c);
if(c == EOF)
{ break; }
}
}
}
else
{
printf("Unable to open temporary file\n");
}
fclose(file);
}
else
{
printf("Unable to open file.");
}
getchar();
return 0;
}
UPDATE:
I've modified a few lines and have got it working.
I'd forgotten to assign c in the above program. Also #Barmar won't char c work just as well as int c. Characters can be integers as well right?
Why would large indentations lead to bugs? I find the blocks of code to be more differetiated.
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#define BUFFER_SIZE 1000
#define FILE_NAME "data.csv"
int main()
{
// Variable Declaration
FILE* file;
char buffer[BUFFER_SIZE];
// Opening file
if( file = fopen(FILE_NAME, "r+") )
{
char c; // Reading characters from the file
int i; // Index of the characters
int isEmpty = 1; // 1-> character is empty; 0-> character is not empty
FILE* tmp;
if( tmp = fopen("tmp.csv", "a+") )
{
char c; // Reading characters from files
int i = 0; // Index
int isEmpty = 1; // 1->previous word is empty; 0->previous word is not empty
while( (c = getc(file)) != EOF)
{
if( c != '\n' && c != ' ' && c != '\0' && c != ',')
{
isEmpty = 0;
buffer[i++] = c;
}
else
{
if( c == '\n' && isEmpty == 0 )
{
buffer[i] = '\0';
fprintf(tmp, "%s", buffer);
i = 0;
isEmpty = 1;
}
else if( c == '\n' && isEmpty == 1 )
{
buffer[i] = '\0';
i = 0;
}
}
}
fclose(tmp);
}
else
{
printf("Unable to open temporary file\n");
}
fclose(file);
}
else
{
printf("Unable to open file\n");
}
return 0;
}
Are there are ways to simplify the program and make it more compact or less error prone?
Stack Overflow! I am on my learning process with the C technology. I have a function which gets an input file, seeks through the file and writes the contents to the output file without the comments.
The function works but it also brakes at some cases.
My Function:
void removeComments(char* input, char* output)
{
FILE* in = fopen(input,"r");
FILE* out = fopen(ouput,"w");
char c;
while((c = fgetc(in)) != EOF)
{
if(c == '/')
{
c = fgetc(in);
if(c == '/')
{
while((c = fgetc(in)) != '\n');
}
else
{
fputc('/', out);
}
}
else
{
fputc(c,out);
}
}
fclose(in);
fclose(out);
}
But when I give a file like this as input:
// Parameters: a, the first integer; b the second integer.
// Returns: the sum.
int add(int a, int b)
{
return a + b; // An inline comment.
}
int sample = sample;
When removing the inline comment it fails to reach the '\n' for some reason and it gives output:
int add(int a, int b)
{
return a + b; }
int sample = sample;
[EDIT]
Thanks for helping me! It works with the case I posted but it brakes in another.
Current code:
FILE* in = fopen(input,"r");
FILE* out = fopen(output,"w");
if (in == NULL) {
printf("cannot read %s\n", input);
return; /* change signature to return 0 ? */
}
if (out == NULL) {
printf("cannot write in %s\n", output);
return; /* change signature to return 0 ? */
}
int c;
int startline = 1;
while((c = fgetc(in)) != EOF)
{
if(c == '/')
{
c = fgetc(in);
if(c == '/')
{
while((c = fgetc(in)) != '\n')
{
if (c == EOF) {
fclose(in);
fclose(out);
return; /* change signature to return 1 ? */
}
}
if (! startline)
fputc('\n', out);
startline = 1;
}
else if (c == EOF)
break;
else {
fputc('/', out);
startline = 0;
}
}
else
{
fputc(c,out);
startline = (c == '\n');
}
}
fclose(in);
fclose(out);
When the file contains division the second variable disappears.
Example:
int divide(int a, int b)
{
return a/b;
}
It gives back:
int divide(int a, int b)
{
return a/;
}
after
while((c = fgetc(in)) != '\n');
you need a fputc('\n', out);
Additional remarks :
In
char c;
while((c = fgetc(in)) != EOF)
c must be an int to manage EOF
Just a typo : ouput must be output to compile
You do not manages well the EOF after you read a '/'
You missed to check the result of the fopen
A proposal :
#include <stdio.h>
void removeComments(char* input, char* output)
{
FILE* in = fopen(input,"r");
FILE* out = fopen(output,"w");
if (in == NULL) {
printf("cannot read %s\n", input);
return; /* change signature to return 0 ? */
}
if (out == NULL) {
printf("cannot write in %s\n", output);
return; /* change signature to return 0 ? */
}
int c;
while((c = fgetc(in)) != EOF)
{
if(c == '/')
{
c = fgetc(in);
if(c == '/')
{
while((c = fgetc(in)) != '\n')
{
if (c == EOF) {
fclose(in);
fclose(out);
return; /* change signature to return 1 ? */
}
}
fputc('\n', out);
}
else if (c == EOF) {
fputc('/', out);
break;
}
else
fputc('/', out);
fputc(c, out);
}
else
{
fputc(c,out);
}
}
fclose(in);
fclose(out);
/* change signature to return 1 ? */
}
int main(int argc, char ** argv)
{
removeComments(argv[1], argv[2]);
}
As Tormund Giantsbane says in a remark it is better to completely remove the line containing only a comment (comment starting on the first column), that new proposal does that :
#include <stdio.h>
void removeComments(char* input, char* output)
{
FILE* in = fopen(input,"r");
FILE* out = fopen(output,"w");
if (in == NULL) {
printf("cannot read %s\n", input);
return; /* change signature to return 0 ? */
}
if (out == NULL) {
printf("cannot write in %s\n", output);
return; /* change signature to return 0 ? */
}
int c;
int startline = 1;
while((c = fgetc(in)) != EOF)
{
if(c == '/')
{
c = fgetc(in);
if(c == '/')
{
while((c = fgetc(in)) != '\n')
{
if (c == EOF) {
fclose(in);
fclose(out);
return; /* change signature to return 1 ? */
}
}
if (! startline)
fputc('\n', out);
startline = 1;
}
else if (c == EOF) {
fputc('/', out);
break;
}
else {
fputc('/', out);
fputc(c, out);
startline = 0;
}
}
else
{
fputc(c,out);
startline = (c == '\n');
}
}
fclose(in);
fclose(out);
/* change signature to return 1 ? */
}
int main(int argc, char ** argv)
{
removeComments(argv[1], argv[2]);
}
Compilation and execution :
pi#raspberrypi:/tmp $ gcc -pedantic -Wextra -g r.c
pi#raspberrypi:/tmp $ cat i
// Parameters: a, the first integer; b the second integer.
// Returns: the sum.
int add(int a, int b)
{
return a + b/c; // An inline comment.
}
int sample = sample;
pi#raspberrypi:/tmp $ ./a.out i o
pi#raspberrypi:/tmp $ cat o
int add(int a, int b)
{
return a + b/c;
}
int sample = sample;
As said by DavidC. in a remark if // is placed in a string the result will not be the expected one, it is also the case in a character even illegal (I mean '//' must not be changed), what about the C comments (/* .. // ... */) etc
When removing the inline comment it fails to reach the '\n' for some reason
Well no, if it failed to reach or see the newline at the end of an inline comment then the program would, presumably, consume the entire rest of the file. What it actually fails to do is write such newlines to the output.
Consider your comment-eating code:
while((c = fgetc(in)) != '\n');
That loop terminates when a newline is read. At that point, the newline, having already been read, is not available to be read from the input again, so your general read / write provisions will not handle it. If you want the such newlines to be preserved, then you need to print them in the comment-handling branch.
Additional notes:
fgetc returns an int, not a char, and you need to handle it as such in order to be able to correctly detect end-of-file.
Your program will go into an infinite loop if the input ends with an inline comment that is not terminated by a newline. Such source is technically non-conforming, but even so, you ought to handle it.