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.
Related
I have a main.c file containing one or more preprocessor macros defined:
#include <stdio.h>
#define VALUE 12
int main(void) {
printf("This file is in version %s and contains value %d\n", VERSION, VALUE);
return 0;
}
I want to export a main2.c file with only the #define VERSION "1.0" applied to the original source file.
What I tried:
gcc -DVERSION=\"1.0\" -E will apply ALL the preprocessor directives instead of the single one I want
sed 's/VERSION/\"1.0\"/g' will probably replace more than needed, and will need more work if I need more than a single directive
cppp is a nice tool but may alter the source file a lot. Only supports simple defines with numerical values
Is there any way to execute only parts of preprocessor directives with gcc ?
Partial preprocessing is a nifty idea and exactly what you are looking for. The cppp utility by Brian Raiter only handles #ifdef and #ifndef lines, it does not perform macro substitution as you require.
Here is a utility I just wrote for this purpose: you can define any number of identifiers on the command line with -Didentifier (expands to 1) or -Didentifier= (expands to nothing), -Didentifier=str or simply identifier=str.
It will substitute identifiers only, preserving comments and strings, but some corner cases are not handled, albeit should not be a problem:
no support for non ASCII identifiers.
stdio in #include <stdio.h> will be seen as an identifier that can be substituted.
some numbers will be parsed as 3 tokens: 1.0E+1.
identifiers will not be substituted if they are split on multiple lines with escaped newlines
defining include, ifdef and other preprocessing directives will cause them to be substituted, unlike the C preprocessor
macro argument names may be substituted whereas the C preprocessor would preserve them.
pcpp.c:
/* Partial preprocessing by chqrlie */
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct define_t {
struct define_t *next;
size_t len;
const char *tok;
const char *def;
} define_t;
static void *xmalloc(size_t size) {
void *p = malloc(size);
if (!p) {
fprintf(stderr, "pcpp: cannot allocate memory\n");
exit(1);
}
return p;
}
static void add_define(define_t **defsp, const char *str) {
define_t *dp = xmalloc(sizeof(*dp));
size_t len = strcspn(str, "=");
const char *def = str[len] ? str + len + 1 : "1";
dp->len = len;
dp->tok = str;
dp->def = def;
dp->next = *defsp;
*defsp = dp;
}
struct context {
FILE *fp;
int lineno;
size_t size, pos;
char *buf;
};
static int append_char(struct context *ctx, int ch) {
if (ctx->pos == ctx->size) {
size_t new_size = ctx->size + ctx->size / 2 + 32;
char *new_buf = xmalloc(new_size);
memcpy(new_buf, ctx->buf, ctx->size);
free(ctx->buf);
ctx->buf = new_buf;
ctx->size = new_size;
}
ctx->buf[ctx->pos++] = (char)ch;
return ch;
}
static void flush_context(struct context *ctx, FILE *ft) {
if (ctx->pos) {
fwrite(ctx->buf, ctx->pos, 1, ft);
ctx->pos = 0;
}
}
/* read the next byte from the C source file, handing escaped newlines */
static int getcpp(struct context *ctx) {
int ch;
while ((ch = getc(ctx->fp)) == '\\') {
append_char(ctx, ch);
if ((ch = getc(ctx->fp)) != '\n') {
ungetc(ch, ctx->fp);
return '\\';
}
append_char(ctx, ch);
ctx->lineno += 1;
}
if (ch != EOF)
append_char(ctx, ch);
if (ch == '\n')
ctx->lineno += 1;
return ch;
}
static void ungetcpp(struct context *ctx, int ch) {
if (ch != EOF && ctx->pos > 0) {
ungetc(ch, ctx->fp);
ctx->pos--;
}
}
static int preprocess(const char *filename, FILE *fp, const char *outname, define_t *defs) {
FILE *ft = stdout;
int ch;
struct context ctx[1] = {{ fp, 1, 0, 0, NULL }};
if (outname) {
if ((ft = fopen(outname, "w")) == NULL) {
fprintf(stderr, "pcpp: cannot open output file %s: %s\n",
outname, strerror(errno));
return 1;
}
}
while ((ch = getcpp(ctx)) != EOF) {
int startline = ctx->lineno;
if (ch == '/') {
if ((ch = getcpp(ctx)) == '/') {
/* single-line comment */
while ((ch = getcpp(ctx)) != EOF && ch != '\n')
continue;
if (ch == EOF) {
fprintf(stderr, "%s:%d: unterminated single line comment\n",
filename, startline);
//break;
}
//putc('\n', ft); /* replace comment with newline */
flush_context(ctx, ft);
continue;
}
if (ch == '*') {
/* multi-line comment */
int lastc = 0;
while ((ch = getcpp(ctx)) != EOF) {
if (ch == '/' && lastc == '*') {
break;
}
lastc = ch;
}
if (ch == EOF) {
fprintf(stderr, "%s:%d: unterminated comment\n",
filename, startline);
//break;
}
//putc(' ', ft); /* replace comment with single space */
flush_context(ctx, ft);
continue;
}
if (ch != '=') {
ungetcpp(ctx, ch);
}
flush_context(ctx, ft);
continue;
}
if (ch == '\'' || ch == '"') {
int sep = ch;
const char *const_type = (ch == '"') ? "string" : "character";
while ((ch = getcpp(ctx)) != EOF) {
if (ch == sep)
break;;
if (ch == '\\') {
if ((ch = getcpp(ctx)) == EOF)
break;
}
if (ch == '\n') {
fprintf(stderr, "%s:%d: unescaped newline in %s constant\n",
filename, ctx->lineno - 1, const_type);
/* This is a syntax error but keep going as if constant was terminated */
break;
}
}
if (ch == EOF) {
fprintf(stderr, "%s:%d: unterminated %s constant\n",
filename, startline, const_type);
}
flush_context(ctx, ft);
continue;
}
if (ch == '_' || isalpha(ch)) {
/* identifier or keyword */
define_t *dp;
while (isalnum(ch = getcpp(ctx)) || ch == '_')
continue;
ungetcpp(ctx, ch);
for (dp = defs; dp; dp = dp->next) {
if (dp->len == ctx->pos && !memcmp(dp->tok, ctx->buf, ctx->pos)) {
/* matching symbol */
fputs(dp->def, ft);
ctx->pos = 0;
break;
}
}
flush_context(ctx, ft);
continue;
}
if (ch == '.' || isdigit(ch)) {
/* preprocessing number: should parse precise syntax */
while (isalnum(ch = getcpp(ctx)) || ch == '.')
continue;
ungetcpp(ctx, ch);
flush_context(ctx, ft);
continue;
}
flush_context(ctx, ft);
}
if (outname) {
fclose(ft);
}
free(ctx->buf);
return 0;
}
int main(int argc, char *argv[]) {
char *filename = NULL;
char *outname = NULL;
define_t *defs = NULL;
FILE *fp;
int i;
for (i = 1; i < argc; i++) {
char *arg = argv[i];
if (*arg == '-') {
if (arg[1] == 'h' || arg[1] == '?' || !strcmp(arg, "--help")) {
printf("usage: pcpp [-o FILENAME] [-Dname[=value]] ... [FILE] ...\n");
return 2;
} else
if (arg[1] == 'o') {
if (arg[2]) {
outname = arg + 2;
} else
if (i + 1 < argc) {
outname = argv[++i];
} else {
fprintf(stderr, "pcpp: missing filename for -o\n");
return 1;
}
} else
if (arg[1] == 'D') {
if (arg[2]) {
add_define(&defs, arg + 2);
} else
if (i + 1 < argc) {
add_define(&defs, argv[++i]);
} else {
fprintf(stderr, "pcpp: missing definition for -D\n");
return 1;
}
} else {
fprintf(stderr, "pcpp: bad option: %s\n", arg);
return 1;
}
} else
if (strchr(arg, '=')) {
add_define(&defs, arg);
} else {
filename = arg;
if ((fp = fopen(filename, "r")) == NULL) {
fprintf(stderr, "pcpp: cannot open input file %s: %s\n",
filename, strerror(errno));
return 1;
}
preprocess(filename, fp, outname, defs);
fclose(fp);
}
}
if (!filename) {
preprocess("<stdin>", stdin, outname, defs);
}
return 0;
}
EDIT: This is a non maintainable solution - but it works. Don't use this if you expect your project to grow into several versions over time.
My attempt makes use of preprocessor conditional code and string concatenation (the fact that in C you can do "abc" "def"and it will be trated as "abcdef".
#include <stdio.h>
#ifdef V1
#define VERSION "1"
#define VALUE 99
#else
#define VERSION "2"
#define VALUE 66
#endif
int main(void) {
printf("This file is in version " VERSION " and contains value %d\n", VALUE);
return 0;
}
which prints
>> ~/playground/so$ gcc -DV1 q1.c
>> ~/playground/so$ ./a.out
This file is in version 1 and contains value 99
>> ~/playground/so$ gcc -DV2 q1.c
>> ~/playground/so$ ./a.out
This file is in version 2 and contains value 66
Read about autoconf https://www.gnu.org/software/autoconf/
and maybe even about automaker (if you want to generate makefiles) https://www.gnu.org/software/automake/.
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?
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);
}
I have written code to remove comments from a C program file, and print the output on the console:
#include <stdio.h>
#include <stdlib.h>
void incomment(FILE *fp);
void rcomment(int c, FILE *fp);
void echo_quote(int c, FILE *fp);
int main() {
FILE *fp;
fp = fopen("temp.c", "r");
int c;
while ((c = getc(fp)) != EOF) {
rcomment(c, fp);
}
return 0;
}
void incomment(FILE* fp) {
int c, d;
c = getc(fp);
d = getc(fp);
while (c != '*' && d != '/') {
c = d;
d = getc(fp);
}
}
void echo_quote(int c, FILE *fp) {
int d;
putchar(c);
while ((d = getc(fp)) != c) {
putchar(d);
if (d == '\\')
putchar(getc(fp));
}
putchar(d);
}
void rcomment(int c, FILE *fp) {
int d;
if (c == '/') {
if ((d = getc(fp)) == '*')
incomment(fp);
else
if (d == '/') {
putchar(c);
rcomment(d, fp);
} else {
putchar(c);
putchar(d);
}
} else
if (c == '\'' || c == '"')
echo_quote(c, fp);
else
putchar(c);
}
However for the following input:
#include<stdio.h>
/* Author : XYZ
* Date : 21/1/2016
*/
int main()
{
int a; // / variable a
printf("/*Hi*/");
return 0;
}
OUTPUT:
#include<stdio.h>
Date : 21/1/2016
*/
int main()
{
int a; // / variable a
printf("/*Hi*/");
return 0;
}
Could someone point out the error in the code. It seems to be working fine for comments within quotes. But not for the single line comments.
The rcomment() function does not parse the single line comments correctly:
If you match a '/' for the second character, you should read all remaining characters upto the newline and output just the newline.
If the second character is a quote, you fail to output the first character and parse the literal. An easy way to do this is to unget the second character with ungetc(d, fp); and only output c.
There are other special cases you do not handle:
Escaped newlines should be handled in literals and single line comments as well as in between the / and the * at the start of a multi-line comment and between the * and the / at the end. You can do this simply by using a utility function to read the bytes from the file that handles escaped newlines but it will be difficult to output them back to the output file to preserve the line counts.
You should replace multiline comments with a single space or newline characters to avoid pasting tokens and to preserve the line count.
incomment() and echo_quote() should handle a premature end of file. As currently coded, they run indefinitely.
This parsing task is more subtile than it looks. You could try another approach and implement a state machine.
Here is a quick fix for the rcomment() function, but the other issues above remain:
int peekc(FILE *fp) {
int c = getc(fp);
if (c != EOF)
ungetc(c, fp);
return c;
}
void rcomment(int c, FILE *fp) {
int d;
if (c == '/') {
if ((d = getc(fp)) == '*') {
incomment(fp);
} else
if (d == '/') {
while ((c = getc(fp)) != EOF && c != '\n') {
if (c == '\\' && peekc(fp) == '\n') {
putchar(getc(fp));
}
}
putchar('\n');
} else {
putchar(c);
ungetc(d, fp);
}
} else
if (c == '\'' || c == '"') {
echo_quote(c, fp);
} else {
putchar(c);
}
}
I am trying to test if the character in a file.txt is a space ' ' or not using this code:
char *Appartient (FILE *f, char *S)
{
int i = 0, nbdechar = 0, nbocc = 0, PosdePremierChar, space = 0;
char c;
while ((c = getc(f)) != EOF) {
PosdePremierChar = ftell(f);
if (c == S[0]) {
nbdechar = 0;
for (i = 1; i < strlen(S); i++) {
c = getc(f);
if (c == S[i]) {
nbdechar++;
}
}
if (nbdechar == strlen(S) - 1) {
nbocc++;
} else {
rewind(f);
fseek(f, PosdePremierChar - 1, SEEK_CUR);
while ((c = getc(f)) != ' ');
}
} else {
while ((c = getc(f)) != ' ') {
space++;
}
}
}
printf("\n Le nb d'occurence est %d", nbocc);
if (nbocc == 0) {
return "false";
} else {
return "true";
}
}
but a weird symbol 'ے' appear like a garbage when I inspect the variable 'c' in my debugger:
What is wrong
Could be the result of converting the end-of-file result from getc(), EOF, (which is standardized to be negative, often -1) to a character.
Note that your loop never terminates if there's no space in the file, since EOF != ' ' and that condition keeps being true after you hit end-of-file for the first time.
Modify your code like this, trace it and you might become enlightened regarding the relation between what getc() returns and how this correlates to chars:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int result = EXIT_SUCCESS;
FILE * f = fopen("test.txt", "r");
if (NULL == f)
{
perror("fopen() failed");
result = EXIT_FAILURE;
}
else
{
int result = EOF;
while (EOF != (result = getc(f)))
{
char c = result;
printf("\n%d is 0x%02x is '%c'", result, result, c);
if (' ' == c)
{
printf(" is space ");
}
}
printf("\nread EOF = %d = 0x%x\n", result, result);
fclose(f);
}
return result;
}
You didn't test if f opened, in case it didn't then undefined behavior will happen, check if the file opened
FILE *file;
int chr;
if ((file = fopen("test.txt", "r")) == NULL)
{
fprintf(stderr, "Cannot open `test.txt'\n");
return -1;
}
while (((chr = fgetc(file)) != EOF) && (chr == ' '))
printf("space\n");
You should declare chr of type int, because fgetc() returns an int, as for example EOF requires to be an int and not a char.
Also, debug mode is useful for tracking the values of variables, I bet that it can five you the value in ascii or decimal or hex, as you need if you know how to ask.