C function to find lines that differ from each other - c

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);
}

Related

How to merge the contents of two files into a new file, appearing side by side by line?

I've been trying to merge the contents of two .txt files into a third .txt file that combines the output. All I know how to do (and all I have been able to find answers for), however, is to merge them by putting the contents of the first file first, and the second file second. However, I would prefer the output to list the first line of the first file, then the first line of the second file -- followed on a new line by the second line of the first file and the second line of the second file.
To make this clearer visually, the code is currently appearing as:
file1-line1
file1-line2
file1-line3
file2-line1
file2-line2
file2-line3
... When I'd like it to appear as:
file1-line1 file2-line1
file1-line2 file2-line2
file1-line3 file2-line3
The code I have is very basic and executes the first example fine:
int main()
{
FILE *pointer1 = fopen("file1.txt", "r");
FILE *pointer2 = fopen("file2.txt", "r");
FILE *pointer3 = fopen("combined.txt", "w");
int ch;
if (pointer1 == NULL || pointer2 == NULL || pointer3 == NULL)
{
puts("Could not open files");
exit(0);
}
while ((ch = fgetc(pointer1)) != EOF)
fputc(ch, pointer3);
while ((ch = fgetc(pointer2)) != EOF)
fputc(ch, pointer3);
printf("Merged file1.txt and file2.txt into combined.txt");
fclose(pointer1);
fclose(pointer2);
fclose(pointer3);
return 0;
}
Is there a way to output the described situation? I am aware that E0F refers to the end of a file, and is likely causing an issue. Is there a similar condition for an end of a line (like E0L)?
Edit: Changed char ch to int ch.
First, if you have a Unix-like system, the paste command already does that. Next as you want to process lines, you should use fgets. Here you have to loop over input files one line at a time, copy the lines to the output file without the newline, and add the new line after copying everything.
As the processing for both input files is the same, and as I am lazy, I wrote a function to only write it once. In the end code could be:
FILE *copyline(FILE *in, FILE *out) {
char line[256];
if (in != NULL) {
for (;;) { // loop if the line is larger that sizeof(line)
if (NULL == fgets(line, sizeof(line), in)) { // EOF on file1
fclose(in);
in = NULL;
break;
}
size_t end = strcspn(line, "\n");
if (end != 0) fwrite(line, 1, end, out); // smth to write
if (end != strlen(line)) break; // \n found: exit loop
}
}
return in;
}
int main()
{
FILE *pointer1 = fopen("file1.txt", "r");
FILE *pointer2 = fopen("file2.txt", "r");
FILE *pointer3 = fopen("combined.txt", "w");
const char sep[] = " "; // a separator between lines of both file
if (pointer1 == NULL || pointer2 == NULL || pointer3 == NULL)
{
puts("Could not open files");
exit(0);
}
for (;;) {
pointer1 = copyline(pointer1, pointer3);
fwrite(sep, strlen(sep), 1, pointer3);
pointer2 = copyline(pointer2, pointer3);
if (pointer1 == NULL && pointer2 == NULL) break;
fputc('\n', pointer3); // if smth was written, add a newline
printf(".");
}
printf("Merged file1.txt and file2.txt into combined.txt");
fclose(pointer3);
return 0;
}
Here's one way to approach it:
#include <err.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
FILE *
xfopen(const char *path, const char *mode)
{
FILE *fp = path[0] != '-' || path[1] != '\0' ? fopen(path, mode) :
*mode == 'r' ? stdin : stdout;
if( fp == NULL ) {
perror(path);
exit(EXIT_FAILURE);
}
return fp;
}
int
main(int argc, char **argv)
{
if( argc < 3 ) {
printf("usage: %s file1 file2\n", basename(argv[0]));
}
FILE *pointer1 = xfopen(argv[1], "r");
FILE *pointer2 = xfopen(argv[2], "r");
FILE *current = pointer1;
int ch;
while( ( ch = fgetc(current)) != EOF ) {
if( ch == '\n' ) {
if( current == pointer1 ) {
int k;
current = pointer2;
if( (k = fgetc(current)) != EOF ) {
ungetc(k, current);
ch = ' ';
}
} else {
current = pointer1;
}
}
putchar(ch);
}
if( ferror(current) ) {
err(EXIT_FAILURE, "Error reading %s",
current == pointer1 ? argv[1] : argv[2]);
}
current = current == pointer1 ? pointer2 : pointer1;
while( (ch = fgetc(current)) != EOF) {
putchar(ch);
}
fclose(pointer1);
fclose(pointer2);
return 0;
}
#include <stdio.h>
int main()
{
FILE *pointer1 = fopen("file1.txt", "r");
FILE *pointer2 = fopen("file2.txt", "r");
FILE *pointer3 = fopen("combined.txt", "w");
char ch1, ch2;
if (pointer1 == NULL || pointer2 == NULL || pointer3 == NULL)
{
puts("Could not open files");
return 0;
}
do
{
char c1 = fgetc(pointer1);
char c2 = fgetc(pointer2);
if (feof(pointer1) || feof(pointer2))
break;
while(c1!='\n')
{
fputc(c1,pointer3);
c1=fgetc(pointer1);
if(feof(pointer1)) break;
}
fputc(' ',pointer3);
while(c2!='\n')
{
fputc(c2,pointer3);
c2=fgetc(pointer2);
if(feof(pointer2)) break;
}
fputc('\n',pointer3);
} while (1);
printf("Merged file1.txt and file2.txt into combined.txt");
fclose(pointer1);
fclose(pointer2);
fclose(pointer3);
return 0;
}
This works like you want.
Output: Combined file.txt
file1-line1 file2-line1
file1-line2 file2-line2
file1-line3 file2-line3

How to remove single character from line read from file in C

How can I remove the "#" from "#2" is a .asm file? My output is currently incorrect when read from the file, but when using just "2" it produces the proper binary result.
FILE *fp;
char buffer[256];
fp = fopen("Add.asm", "r");
if(fp == NULL){
printf("Error opening file\n");
}
else{
while(fgets(buffer, 256, fp) != NULL){
buffer[strcspn(buffer, "\r\n")] = 0;
printf("Buffer:");
printf("%s\n",buffer);
if(aOrC(buffer) == true){
int changer = stringToInt(buffer);
printf("%s\n",intToBinary(changer));
} else if(aOrC(buffer) == false){
char* jump = jumpBits(buffer);
char* dest = destBits(buffer);
char* comp = compBits(buffer);
char* finalBits = finalBinaryC(comp, dest, jump);
printf("%s\n", finalBits);
}
}
fclose(fp);
}
The Add.asm file is below and from the nand2tetris project.
#2
D=A
#3
D=D+A
#0
M=D
Based on your output the # comes always at the beginning of the strings. So
you can easily do this:
// str contains the string "#2"
puts(str + (str[0] == '#' ? 1 : 0));
If you want to remove a # at some random position, then you should write a
function like this
char *remove_char(char *src, char c)
{
if(src == NULL)
return NULL;
char *p = strchr(src, c);
if(p == NULL)
return src; // c not found
// removing c
memmove(p, p+1, strlen(p));
return src;
}
Then you can call it like
char line[] = "abc#def";
puts(remove_char(line, '#'));
This would print abcdef

How to get back pointer of pointers from a function

I have a function which open a file, read its content line by line and then push it to an array. I have managed to get the array functionnal inside the right function, but when I want to get it back to my main function, I cannot get any items of my array.
Some code will help you to understand:
My main function:
/* ----------------- MAIN ------------ */
int main(int argc, char *argv[]) {
/*... some useless code for now ... */
char **ptrLines = NULL;
ptrLines = readEventFile(ptrParam, ptrLines);
outputExecTrace(WAR, "PTRLINES x : %x", ptrLines);
outputExecTrace(WAR, "PTRLINES char[] : %s", *(ptrLines + 2));
return EXIT_SUCCESS;
}
My fileReader function:
char** readEventFile(Parameters *parameters, char **arrLine) {
FILE *fp = fopen(parameters->inputFilePath, "r");
if (fp == NULL)
exit(0);
char line[128];
int nbCharOfLine = 0;
while(1) {
fgets(line, sizeof(line), fp);
if (feof(fp))
break;
nbCharOfLine++;
}
fclose(fp);
arrLine = malloc(sizeof(line) * nbCharOfLine);
nbCharOfLine = 0;
fp = fopen(parameters->inputFilePath, "r");
while(1) {
fgets(line, sizeof(line), fp);
if (line[0] != '#') {
arrLine[nbCharOfLine] = malloc((strlen(line)+1) * sizeof(char));
strcpy(arrLine[nbCharOfLine], line);
nbCharOfLine++;
}
if (feof(fp))
break;
}
fclose(fp);
outputExecTrace(WAR, "ARRLINE x : %x", arrLine);
outputExecTrace(WAR, "ARRLINE char[] : %s", *(arrLine + 2));
return arrLine;
}
Has it is, my outputs are the followings:
WARNING: ARRLINE int : -2020552688
WARNING: ARRLINE char[] : 1 3 4 //This is the result I am looking for.
WARNING: PTRLINES int : -2020552688 // Same as ARRLINE
Segmentation fault (core dumped) // And this is because ptrLines[2] doesn't contains anything... but why ?!
How can I fix this ?
It's hard to tell exactly what happen, because you have several small problems within code, which could lead to this, try to change your code in following way:
char** readEventFile(char* fileName) {
char line[128];
int nbCharOfLine = 0;
FILE *fp = fopen(fileName, "r");
if (fp == NULL)
exit(1);
while (!feof(fp)) {
char *r = fgets(line, sizeof(line), fp); // NOTE: proper handling of fgets return value
if ((r != NULL) && (line[0] != '#'))
nbCharOfLine++;
}
fclose(fp);
char **arrLine = calloc(nbCharOfLine, sizeof(char*)); // use calloc to be sure
nbCharOfLine = 0;
fp = fopen(fileName, "r");
while (!feof(fp)) {
char *r = fgets(line, sizeof(line), fp);
if ((r != NULL) && (line[0] != '#')) {
arrLine[nbCharOfLine] = calloc(strlen(line) + 1, sizeof(char));
strcpy(arrLine[nbCharOfLine++], line);
}
}
fclose(fp);
return arrLine;
}
in your main, you will call this function like:
char **ptrLines = readEventFile(ptrParam->inputFilePath);
Not so sure this is the whole problem, but the posted code:
while(1) {
fgets(line, sizeof(line), fp);
if (line[0] != '#') {
arrLine[nbCharOfLine] = malloc((strlen(line)+1) * sizeof(char));
strcpy(arrLine[nbCharOfLine], line);
nbCharOfLine++;
}
if (feof(fp))
break;
}
is not the right approach for several reasons,
including that function feof()
is only asserted 'true' when the code has tried to read past the
end of the file.
suggest:
while( fgets(line, sizeof(line), fp) )
{
if (line[0] != '#')
{
if( NULL == (arrLine[nbCharOfLine] = malloc((strlen(line)+1) * sizeof(char)) ) )
{ // then, malloc failed
perror( "malloc failed" );
// close file and free all malloc'd areas
exit( EXIT_FAILURE );
}
// implied else, malloc successful
strcpy(arrLine[nbCharOfLine], line);
nbCharOfLine++;
}
}

Having problems with assert in c

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);

"aborted (core dumped)" in all programs

yesterday, during programming time everything was okay, but today I get weird error. I do not know why but after running my programs, in terminal i get this error "aborted (core dumped)", also I run programs which are already done and the problem is the same.
Example of the program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define CHUNK 12
char *getWord(FILE *infile);
int main(int argc, char *argv[])
{
char *word;
FILE *infile, *outfile;
int n = 0;
if(argc != 2)
{
printf("Error! Type:./file_name input_file output_file\n");
abort();
}
infile = fopen(argv[1], "r");
if(infile != NULL)
{
outfile = fopen(argv[2], "w");
if(outfile == NULL)
{
printf("Error! Cannot open the output_file\n");
abort();
}
else
{
while(!feof(infile))
{
word = getWord(infile);
if(word == NULL)
{
free(word);
abort();
}
n++;
if(n % 2 == 0)
{
fputs(word, outfile);
fputs(" ", outfile);
}
else
{
fputs(word, outfile);
fputs("(", outfile);
fputs(word, outfile);
fputs(")", outfile);
fputs(" ", outfile);
}
free(word);
}
}
}
else
{
printf("Error! Cannot open the input_file\n");
abort();
}
fclose(infile);
fclose(outfile);
return 0;
}
char *getWord(FILE *infile)
{
char *word, *word2;
int length, cursor, c;
word = malloc(sizeof(char)*CHUNK);
if(word == NULL)
{
return NULL;
}
length = CHUNK;
cursor = 0;
while(isalpha(c = getc(infile)) && !feof(infile))
{
word[cursor] = c;
cursor++;
if(cursor >= length)
{
length += CHUNK;
word2 = realloc(word, length*sizeof(char));
if(word2 == NULL)
{
free(word2);
return NULL;
}
else word2 = word;
}
}
ungetc(c, infile);
word[cursor] = '\0';
return word;
}
and the error:
Error! Type:./file_name input_file output_file
Aborted (core dumped)
The logic in your realloc is wrong.
word2 = realloc(word, length*sizeof(char));
if(word2 == NULL)
{
free(word2);
return NULL;
}
else word2 = word;
should be
word2 = realloc(word, cursor);
if(word2 == NULL)
{
free(word);
return NULL;
}
word = word2;
There are a few changes here
word starts out having length bytes allocated so there is no point in reallocating it to the same size. The variable which tracks string size is cursor so you need to reallocate to match its size.
(minor) There is no need to use sizeof(char) to help calculate the size of an allocation - this is guaranteed to be 1
If realloc fails, you need to free the original pointer, not the new one (which you know is NULL).
If the reallocation succeeds, your heap cell may have been moved, leaving word pointing to memory you don't own. The rest of the function operates on word so you need to update it to point to your new buffer (word2)
As for why this worked for you previously, the above code results in undefined behaviour in a number of places. Sometimes you're unlucky and this appears to work correctly.
If your command requires 2 parameters, you need to check for argc != 3 since the command name itself is considered an argument. If you are giving it 2 parameters, then your check on argc != 2 is failing and you're getting your error message, and the core dump due to the abort call.
Rather than abort, you should call exit with a non-zero parameter. E.g.,
if(argc != 3)
{
printf("Error! Type: %s input_file output_file\n", argv[0]);
exit(1);
}

Resources