I'm working on a programming assignment at the moment where the objective is to compare hashing strategies. For the main part of the program, the user is allowed to use it with options (using getopt).
The problem I'm trying to solve is that I have an option that tells the program to scan through a dictionary and compares words given in from stdin with the words in the dictionary, and prints the words with differences (words from stdin). Here is a code partial:
if (flag_c) {
while (getword(word, sizeof word, fopen(filename, "r")) != EOF) {
start = clock();
if (htable_search(h, word) == 0) {
fprintf(stderr, "%s\n", word);
unknown_word_count++;
}
search_time += (clock() - start) / (double) CLOCKS_PER_SEC;
}
printf("Fill time : %f\n", fill_time);
printf("Search time : %f\n", search_time);
printf("Unknown words = %d\n", unknown_word_count);
}
Now I think the problem lies in the while loop conditon. The getword function is defined below:
int getword(char *s, int limit, FILE *stream) {
int c;
char *w = s;
assert(limit > 0 && s != NULL && stream != NULL);
/* skip to the start of the word */
while (!isalnum(c = getc(stream)) && EOF != c)
;
if (EOF == c) {
return EOF;
} else if (--limit > 0) { /* reduce limit by 1 to allow for the \0 */
*w++ = tolower(c);
}
while (--limit > 0) {
if (isalnum(c = getc(stream))) {
*w++ = tolower(c);
} else if ('\'' == c) {
limit++;
} else {
break;
}
}
*w = '\0';
return w - s;
}
When I run the program I get the error:
Test: mylib.c:10: getword: Assertion `limit > 0 && s != ((void *)0) && stream != ((void *)0)' failed.
Aborted (core dumped)
I'm really not too sure why this is happening. Any ideas?
You are using fopen in the while loop:
while (getword(word, sizeof word, fopen(filename, "r")) != EOF) {
Does getword close the FILE*? If not you have a lot of open file handles.
What you probably need is:
Open the file before the start of the while loop.
Use the FILE* in the loop.
Close the file after you get out of the while loop.
FILE* fp = fopen(filename, "r");
if ( fp == NULL )
{
// Deal with error condition.
}
while (getword(word, sizeof word, fp) != EOF) {
start = clock();
if (htable_search(h, word) == 0) {
fprintf(stderr, "%s\n", word);
unknown_word_count++;
}
search_time += (clock() - start) / (double) CLOCKS_PER_SEC;
}
fclose(fp);
Related
I am trying to implement the function that compares two files. The function should restore the first lines that differ from each other. If the files are the same, NULL will be returned. The function ends as soon as either of the files ends, and then NULL is returned. I think my if functions doesn't work and so on this function don't return the lines.
Here is my code:
char *difference(const char* file1, const char* file2)
{
char line1[1000];
char line2[1000];
char *a = malloc(1000 * sizeof(char));
FILE *f1 = fopen(file1, "r");
FILE *f2 = fopen(file2, "r");
if (!f1 || !f2) // checking if there is any error
{
return -1;
}
while (fgets(line1, sizeof(line1), file1) != NULL && fgets(line2, sizeof(line2), file1) != NULL)
{
if (strcmp(line1, line2) != 0)
{
strcpy(a, line1);
strcpy(a, line2);
}
else
{
return NULL;
}
}
fclose(f1);
fclose(f2);
return a;
int main(void)
char* diff = difference("testifile.c", "testifile2.c");
printf("\n--- Difference:\n");
printf("%s", diff);
free(diff);
return 0;
}
Yeah that doesn't work so good. Here are the bugs:
return -1;
Does not compile. Did you mean
return (char*)-1;
Also, leaks memory. Do:
if (f1) fclose(f1);
if (f2) fclose(f2);
return (char*)-1;
Oops you read from file1 twice:
while (fgets(line1, sizeof(line1), file1) != NULL && fgets(line2, sizeof(line2), file1) != NULL)
should be
while (fgets(line1, sizeof(line1), file1) != NULL && fgets(line2, sizeof(line2), file2) != NULL)
Memory trashing:
line3=strcat(line1,line2);
Should be:
strcat(strcpy(a,line1),line2);
Only ever checks first line because early return:
else
{
return NULL;
}
Just eliminate that block.
Oops forgot to check for errors:
char* diff = difference("testifile.c", "testifile2.c");
char* diff = difference("testifile.c", "testifile2.c");
if (diff == (char *)-1) {
/* handle file open error */
}
else if (diff == NULL) {
/* handle no difference */
}
else {
/* your message */
free(diff);
}
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
void handle(FILE *np)// this is to handle newline characters
{
putc('\n', np);
}
/* skip a C multi-line comment, return the last byte read or EOF */
int m_cmnt(FILE *fp, int *lineno_p) {
FILE *np = stdout;
int prev, ch, replacement = ' ';
for (prev = 0; (ch = getc(fp)) != EOF; prev = ch) {
if (prev == '\\' && ch == 'n') {
replacement = '\n';
++*lineno_p;
}
if (prev == '*' && ch == '/')
return replacement;
}
return EOF;
}
int main(int argc, char *argv[]) {
FILE *fp = stdin, *np = stdout;
int ch,prev;
bool String = 0;
const char *filename = "<stdin>";
int lineno = 1;
fp = fopen(filename, "r");
np = fopen(argv[2], "w");
if (argc > 1) {
if ((fp = fopen(filename = argv[1], "r")) == NULL) {
fprintf(stderr, "Cannot open input file %s: \n",
filename);
exit(EXIT_FAILURE);
}
}
if (argc > 2) {
if ((np = fopen(argv[2], "w")) == NULL) {
fprintf(stderr, "Cannot open output file %s: \n",
argv[2]);
exit(EXIT_FAILURE);
}
}
while ((ch = getc(fp)) != EOF) {
if (ch == '\n')
lineno++;
/* file pointer currently not inside a string */
if (!String) {
if (ch == '/') {
ch = getc(fp);
if (ch == '\n')
lineno++;
if (ch == '*') {
int startline = lineno;
ch = m_cmnt(fp, &lineno);
if (ch == EOF) {
fprintf(stderr, "%s:%d: error: unterminated comment started on line %d\n",
filename, lineno, startline);
exit(EXIT_FAILURE);
break;
}
putc(ch, np);
} else {
putc('/', np);
putc(ch, np);
}
}
else if ( ch=='\\')/*to handle newline character*/
{
prev=ch ;
ch= getc(fp) ;
switch(ch)
{
case 'n' :
handle(np);
break ;
/*default :
putc(prev , np) ;
putc(ch , np) ;
break ;*/
}
}
else {
putc(ch, np);
}
} else {
putc(ch, np);
}
if (ch == '"' || ch == '\'')
String = !String;
}
fclose(fp);
fclose(np);
//remove(arr[1]);
//rename("temp.txt", arr[1]);
return EXIT_SUCCESS;
}
I have been working on this project for almost more than a week now. I have asked many questions on this site to help me get the desired result.The basics of this program is to remove multiline comments from source file and write the rest to some output file. It also need to to ignore any thing that is inside a string literal or character literal(like escaped characters). Now I have come to finalize it but I still need to achieve this two outputs shown below
INPUT1 = //*SOMECOMMENT*/
OUTPUT1 = /
INPUT2 = "this \"test"/*test*/
OUTOUT2 = "this \"test"
The current(erroneous) output is shown below
INPUT1 = //*SOMECOMMENT*/
OUTPUT1 = //*SOMECOMMENT*/ This is wrong.
INPUT2 = "this \"test"/*test*/
OUTOUT2 = "this \"test"/*test*/ This is also wrong.
The program don't work for the case where a comment comes after a forward slash(/) and the second failure of the program is it don't ignore escape character inside a string or character literal. I need a fix on this two problems please.
If your problem is that you want to read an input stream of characters, divide that stream into tokens, and then emit only a subset of those tokens, I think Lex is exactly the tool you're looking for.
If I understand your comment correctly, the file you're trying to read in and transform is itself C code. So you will need to build up a Lex definition of the C language rules.
A quick search turned up this Lex specification of the ANSI C grammar. I cannot vouch for its accuracy or speak to its licensing. At first glance it seems to only support C89. But it is probably enough to point you in the right direction.
I'm trying to compare 2 text files and print the first line where they differ but I'm using a buffer of 500 in the fgets() command and I think I'm wasting space.
How can I make the same program if I don't know the length of the line?
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
FILE *fp1, *fp2;
int nLine = 1;
char l1[500], l2[500];
system("clear");
if (argc < 3)
{
printf("Usage: %s <file1.txt> <file2.txt>\n",argv[0]);
exit(1);
}
if ((fp1 = fopen(argv[1],"r")) == NULL){
printf("Can't open file: %s\n", argv[1]);
exit(1);
}
if ((fp2 = fopen(argv[2],"r")) == NULL){
printf("Can't open file: %s\n", argv[2]);
exit(1);
}
fgets(l1,500,fp1);
fgets(l2,500,fp2);
while ((l1 != 0) && (l2 != 0)){
if(strcmp(l1,l2) != 0){
printf("Line number: %d\n", nLine);
printf("%s", l1);
printf("%s\n", l2);
exit(1);
} else {
fgets(l1,500,fp1);
fgets(l2,500,fp2);
nLine++;
}
}
return 0;
}
If you do not want to "waste space", remember that the data are in file memory. Read 1 character at time. When you find a difference, just seek to that location of the previous line feed and report the following lines.
long index = 0;
long index_lf = 0;
int c1,c2;
// read until a difference or done
while ((c1 = fgetc(fp1)) == (c2 = fgetc(fp2)) && (c1 != EOF)) {
index++;
if (c1 == '\n') index_lf = index;
}
if (c1 == c2) {
puts("same");
} else {
puts("differ");
fseek(fp1, index_lf, SEEK_SET);
fseek(fp2, index_lf, SEEK_SET);
// read and print each file until a following \n or EOF occurs.
// TBD code for OP
}
[Edit] Some improvements to cope with various issues: mis-match on last byte, files opened in different modes, error handling, etc.
long offset1 = ftell(fp1);;
long offset2 = ftell(fp2);;
int c1,c2;
// read until a difference or done
while ((c1 = fgetc(fp1)) == (c2 = fgetc(fp2)) && (c1 != EOF)) {
if (c1 == '\n') {
offset1 = ftell(fp1);
offset2 = ftell(fp2);
}
}
if (offset1 == -1 || offset2 == -1 || ferror(fp1) || ferror(fp2)) {
puts("problem");
} else if (c1 == c2) {
puts("same");
} else {
puts("differ");
fseek(fp1, offset1, SEEK_SET);
fseek(fp2, offset2, SEEK_SET);
// read and print each file until a following \n or EOF occurs.
// TBD code for OP
}
This is part of the program I am working on, it is copying the file opened and then put it into an array (file1). However, I am getting a segmentation fault when I try to print out the content of the file1.
I had tried to set the MAX_MAC_ADD to 50 and BIG_NUM to 30000 such that it is big enough to sustain the file from fgets().
The file which I am opening has 4 parts, each separate by a 'tab'
e.g. 1one 1two 1three 1four
2one 2two 2three 2four
char file1[MAX_MAC_ADD][BIG_NUM];
int num_MAC = 0;
char *Programe_Name;
int saperate_fields1(char line[])
{
int i = 0;
int f = 0;
while(line[i] != '\0' && line[i] != '\n')
{
int c = 0;
while(line[i] != '\t' && line[i] != '\0' && line[i] != '\n')
{
file1[f][c] = line[i];
++c;
++i;
}
file1[f][c] = '\0';
++f;
if(f == (MAX_MAC_ADD-1))
{
break;
}
++i;
}
return f,i;
}
void read_file1(char filename[])
{
//OPEN FOR READING
FILE *fp = fopen(filename,"r");
if(fp == NULL)
{
printf("%s: cannot open '%s'\n", Programe_Name, filename);
exit(EXIT_FAILURE);
}
char line[BUFSIZ];
while(fgets(line, sizeof line, fp) != NULL)
{
saperate_fields1(line); //SAPERATE INTO FIELDS
num_MAC = num_MAC + 1;
printf("%d times\n", num_MAC);
}
fclose(fp);
printf("line is:\n%s\n", line); //TO CHECK WHERE DO THE PROGRAM STOP READING
printf("file1 is:\n%s\n", file1);
}
You pass a pointer to an array of chars to the format specifier %s which expects a pointer to a char. If you want to print your array of arrays of char you need to print the elements individually, e.g.:
for (int i = 0; i != end; ++i) {
printf("file1[%d]='%s'\n", i, file1[i]);
}
I am trying to read two files in my program I wrote earlier, but it always fails.
char line[BUFSIZ];
FILE *fp2=freopen("source.dat","r");
if(fp2==NULL)
printf("Problm opening: source.dat");
FILE *fp3=freopen("result.dat", "r");
if(fp3==NULL)
printf("Problm opening: result.dat");
char line2[BUFSIZ];
int len;
while( (fgets(line2, BUFSIZ, fp2) != NULL) && (fgets(line, BUFSIZ, fp3) != NULL)) {
len=strlen(line);
if( line[len - 1] == '\n' ) line[len-1] = '\0'; len=strlen(line2);
if( line2[len - 1] == '\n' ) line2[len-1] = '\0';
rename(line, line2);
}
I'm not sure why, I know my program writes the two files I want to open. It just doesn't get past the while loop.
freopen takes 3 arguments viz., filename, mode and FILE Stream object. Hence, to reopen a file, it should already be open. If we invoke a freopen as the first call, the runtime may throw an exception of uninitialized access.
Modifying the code as below
fp2 = fopen("source.dat", "r");
fp3 = fopen("result.dat", "r");
I am able to run your code without any problem and control continues beyond the while loop. The files stored in first file are renamed to the names stored in second file, which I presume is the objective of your program.
This code works for me and apparently should do the same yours does, except where noted.
The first note apparently was the right one :-)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
char line[2][BUFSIZ];
FILE *fp[2];
char *file[2] = { "source.dat", "result.dat" };
int f, finished = 0;
// Any pointers to source and result must be flushed and closed at this point,
// i.e. if this same program has created the files, it must now close them.
for (f = 0; f < 2; f++)
{
if (NULL == (fp[f] = fopen(file[f],"r")))
{
fprintf(stderr, "Error opening %s\n", file[f]);
exit(-1);
}
}
while(!finished)
{
int len;
for (f = 0; f < 2 && (!finished); f++)
{
if (NULL == fgets(line[f], BUFSIZ, fp[f]))
{
fprintf(stderr, "NULL on %s\n", file[f]);
finished = 1;
break;
}
if (feof(fp[f]))
{
fprintf(stderr, "end of %s\n", file[f]);
finished = 1;
break;
}
len = strlen(line[f]);
// if one of the file contains an empty line, program might crash
if (0 == len)
{
fprintf(stderr, "empty line in %s\n", file[f]);
finished = 1;
break;
}
if ('\n' == line[f][len-1])
line[f][len-1] = 0x0;
}
if (finished)
break;
fprintf(stderr, "Rename(%s, %s)\n", line[0], line[1]);
// rename(line, line2);
}
for (f = 0; f < 2; f++)
fclose(fp[f]);
return 0;
}