Doubt FILE in . h

Asked

Viewed 302 times

0

Good friends, I am new to the platform, so I don’t know if I am in the right place. But I would like a help. My problem is to make a program that copies a txt file to another text file, with the function done separately (in library). I’m not getting it. I will put here the files I have already made, main. c and my library (.c and . h).

    #include <stdio.h>
    #include <stdlib.h>
    #include "biblio2.h"

    //main.c//

    int main(void) {

    void copiartxt(FILE *file1, FILE *file2);

    FILE *file1 = fopen("Arquivo 1.txt", "r");
    if(file1==NULL){
        printf("ERRO!");
        return 1;
    }

    FILE *file2 = fopen("Arquivo 2.txt", "w");

    copiartxt(file1, file2);

    fclose(file1);
    fclose(file2);

    return 0;
}


    //biblioteca.h//
    void copiartxt(FILE, FILE);


    //biblioteca.c//
    #include <stdio.h>
    #include <stdlib.h>

    void copiartxt(FILE *file1, FILE *file2){

    char leitor[1000];

    while(fgets(leitor, 1000, file1)!=NULL){
    fputs(leitor, file2);
        }
    return 0;
    }

Could someone tell me what’s wrong?? Thank you very much!!

  • How are you compiling? What error message is displayed? I can already point to half a dozen "mistakes" or "pattern leaks," but I don’t know if it’s really the point that’s actually stopping you

  • Is giving conflict in copiartxt in main. c

  • which error message?

  • In Function 'main': [Error] Conflicting types for 'copiartxt'

  • Which file? And how are you doing to compile?

  • In main.c. I pulled that line from the main program and there were other errors in the library.h. And it’s just in this library. h that I have doubt, because I have never made a program to touch files of this type

  • Oops, I was able to fix it. I should have put "struct FILE *" in the library.h. It worked as expected.

  • By your description, keep using the wrong way. When you have a time I answer the correct

  • Okay buddy. I’m waiting for your version!!

  • Related: https://answall.com/q/307279/64969

Show 5 more comments

2 answers

3


First of all, we need to know the compilation cycle of a C source file. Basically, it goes through the following stages:

  1. preprocessor
  2. compilation for object
  3. linkediting

The linkediting process takes place when constructing the final executable. Intermediate build files stop at step 2 compilation for object. I gave more details in this answer.

Taking some context of the linked answer:

Functions they had forward declaration [are open references].

You can and should create object files with open references. But you can only create executable after closing all static references, after making all the links, all the Binds. And who does that? The linker.

What is this about forward declaration? It is a technique in which I teach the compiler that something will exist further; I declare that something will exist. But, I do not define much about it =) Read more (the example is in C++ but the idea is the same, declare something forward).

But why is it important to meet this forward declaration? Because...

Amazingly, the C compiler works only a single input at a time. It takes that input from the so-called C pre-processor.

Source

The case study: copiartxt

You want to create a function that takes two file pointers, that has no return, and that is called copiartxt. In order to use it in several corners, you have to compile it partially and you can use this result in the linkediting and generate the final executable.

For such a process, there is the file biblioteca.c, which will be transformed into biblioteca.o (or biblioteca.obj, in the Visual Studio world if I’m not mistaken). Let’s build it gradually?

To begin with, shall we focus on her? She will have the function copiartxt desired. So let’s start with this:

void copiartxt(FILE *file1, FILE *file2)
{
  char leitor[1000];

  while (fgets(leitor, 1000, file1) != NULL) {
    fputs(leitor, file2);
  }
}

You may notice that our codes are slightly different. I used my code style, keys positioning and spacing, but also removed the return 0;, since the function should have no return, it is void

If you so to compile, some compilers will complain that they do not know fgets, nor fputs, nor NULL, I believe that also of FILE. These functions and this constant are declared in the file <stdio.h>. About fgets, at some point <stdio,h> you will find a line similar to this (source):

char *fgets(char *str, int n, FILE *stream);

Just like that. Just the statement line of that function. So, we need to insert this header in our biblioteca.c:

#include <stdio.h>

void copiartxt(FILE *file1, FILE *file2)
{
  char leitor[1000];

  while (fgets(leitor, 1000, file1) != NULL) {
    fputs(leitor, file2);
  }
}

All right, now you should compile happy and error free. After compiling up to object code level (gcc -c biblioteca.c, for example), we can use it in our executable.

Now, let’s go to the executable? main.c the name? Well, here we go. The central reason of this file is an application entry point (the function main) that will copy the file "Arquivo 1.txt" to fate "Arquivo 2.txt". Should give some treatment for the bugs too, so come on, encode the function main:

int main(void)
{
  FILE *file1 = fopen("Arquivo 1.txt", "r");
  if (file1 == NULL) {
    fprintf(stderr, "ERRO ao abrir \"Arquivo 1.txt\"!");
    return 1;
  }

  FILE *file2 = fopen("Arquivo 2.txt", "w");
  if (file2 == NULL) {
    fprintf(stderr, "ERRO ao abrir \"Arquivo 2.txt\"!");
    return 1;
  }
  copiartxt(file1, file2);

  fclose(file1);
  fclose(file2);

  return 0;
}

Changes that I made:

  1. removed the forward declaration that was within the function main, then we’ll deal with it
  2. added an error detection to the "Arquivo 2.txt" in the same style you made for "Arquivo 1.txt" (will we are in a read-only file system?)
  3. I put a slightly more specific error message; now you can discern who was the cause of the error
  4. I am printing on error output stderr, for that is where the errors must be printed; for this, it was necessary to use the fprintf

If you try to compile without further changes, the main.c will present some errors. As for example:

  • what is NULL?
  • what is stderr?
  • where the function fprintf?
  • where the function fopen?
  • where the function fclose?
  • where the function copiartxt?

Maybe I’ll complain about what it is FILE, do not remember. How to fix this? Well, a good part is solved by including the <stdio.h>. Then I’d be like this:

#include <stdio.h>

int main(void)
{
  FILE *file1 = fopen("Arquivo 1.txt", "r");
  if (file1 == NULL) {
    fprintf(stderr, "ERRO ao abrir \"Arquivo 1.txt\"!");
    return 1;
  }

  FILE *file2 = fopen("Arquivo 2.txt", "w");
  if (file2 == NULL) {
    fprintf(stderr, "ERRO ao abrir \"Arquivo 2.txt\"!");
    return 1;
  }
  copiartxt(file1, file2);

  fclose(file1);
  fclose(file2);

  return 0;
}

But still no statement of who you are copiartxt. We can use a forward declaration and the compiler will be happy.

ATTENTION: is not the final code

#include <stdio.h>

void copiartxt(FILE *fonte, FILE *destino);

int main(void)
{
  FILE *file1 = fopen("Arquivo 1.txt", "r");
  if (file1 == NULL) {
    fprintf(stderr, "ERRO ao abrir \"Arquivo 1.txt\"!");
    return 1;
  }

  FILE *file2 = fopen("Arquivo 2.txt", "w");
  if (file2 == NULL) {
    fprintf(stderr, "ERRO ao abrir \"Arquivo 2.txt\"!");
    return 1;
  }
  copiartxt(file1, file2);

  fclose(file1);
  fclose(file2);

  return 0;
}

Okay, now the compiler is satisfied. But, will that be right?

You have to declare main.c a thing that is external to it. If there were anything that gave this effect, teach the compiler that there are forward declaration of functions without having to be in the archive main.c...

But, wait a minute! That’s it! That’s what the pre-compilation directive #include does, it "writes" to the source file. So, if there magically exists a biblioteca.h that declares this function, I am done. The code of the main.c would then be:

#include <stdio.h>
#include "biblioteca.h"

int main(void)
{
  FILE *file1 = fopen("Arquivo 1.txt", "r");
  if (file1 == NULL) {
    fprintf(stderr, "ERRO ao abrir \"Arquivo 1.txt\"!");
    return 1;
  }

  FILE *file2 = fopen("Arquivo 2.txt", "w");
  if (file2 == NULL) {
    fprintf(stderr, "ERRO ao abrir \"Arquivo 2.txt\"!");
    return 1;
  }
  copiartxt(file1, file2);

  fclose(file1);
  fclose(file2);

  return 0;
}

Okay, now everyone’s happy. We just need to create the biblioteca.h, right? Actually, more or less... if you want the file header is coherent, who implements the functions he declared should also include the same header. If I don’t make that inclusion, I could set a function copiartxt with another signature, other entries. So this means that it is also necessary to make some changes to the biblioteca.c. In this case, the amendment is simply to include the biblioteca.h and be happy:

#include <stdio.h>
#include "biblioteca.h"

void copiartxt(FILE *file1, FILE *file2)
{
  char leitor[1000];

  while (fgets(leitor, 1000, file1) != NULL) {
    fputs(leitor, file2);
  }
}

Okay, now just create the file biblioteca.h. As always, let’s start at its heart: the forward declaration of function copiartxt:

void copiartxt(FILE *file1, FILE *file2);

Well, now the compiler can complain that he doesn’t know the type FILE. So there’s nothing fairer than teaching at header who he is:

#include <stdio.h>
void copiartxt(FILE *file1, FILE *file2);

Now ready? Well, not yet... files header in C need special care. You normally do not want it to be included more than once in the code. And yes, this can happen. For example, in biblioteca.c, there are two guidelines for inclusion of <stdio.h>; the first, in the archive itself biblioteca.c, and the second time in #include of biblioteca.h. This is part of the pre-processing of the C language. One of the alternatives to doing this is through guardians of inclusion (include Guardians). A classic inclusion guardian uses two pre-processor features:

  1. I can send a text to the compiler in a conditional manner; therefore, I can ignore text in a conditional manner
  2. can declare things

Setting an example of this question:

#ifndef FOO_H_INCLUDED
#define FOO_H_INCLUDED

class Foo
{  
   // código
};

#endif

He’s protecting the code by declaring FOO_H_INCLUDED. So we can use that in our biblioteca.h:

#ifndef BIBLIOTECA_H_INCLUDED
#define BIBLIOTECA_H_INCLUDED

#include <stdio.h>
void copiartxt(FILE *file1, FILE *file2);

#endif

Note that the inclusion guardian should be unique to each header, otherwise you can activate another’s guardian header and cause a confusion

There’s also a certain #pragma once which does something similar to the inclusion guardian, but is more efficient. The problem is that it is not standard, so not all compilers will accept it. Read more.

But why did it work with void copiartxt(struct FILE *origem, struct FILE *destino)?

Basically because, with pointers, several C compilers will ignore whether there is such of the stated structure. Treating only as pointers, many C compilers can make absurd and disgusting mixes, but ultimately they work. That’s why you can use a pointer to a structure that has not been declared (but is called struct FILE).

In the case of <stdio.h>, at no time does she make available to you a struct FILE, because you don’t need to know what a FILE internally. For example, in <stdio.h> made available by GNU, line 51:

typedef struct __sFILE FILE;

Additional notes

If you want C++ compatibility, just include all forward declaration within a block extern "C". But just do it for C++, C doesn’t know blocks extern "C":

#ifndef BIBLIOTECA_H_INCLUDED
#define BIBLIOTECA_H_INCLUDED

#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif

void copiartxt(FILE *file1, FILE *file2);

#ifdef __cplusplus
}
#endif
#endif

In short

Filing cabinet biblioteca.h (compatible with C++):

#ifndef BIBLIOTECA_H_INCLUDED
#define BIBLIOTECA_H_INCLUDED

#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif

void copiartxt(FILE *file1, FILE *file2);

#ifdef __cplusplus
}
#endif
#endif

Filing cabinet biblioteca.c:

#include <stdio.h>
#include "biblioteca.h"

void copiartxt(FILE *file1, FILE *file2)
{
  char leitor[1000];

  while (fgets(leitor, 1000, file1) != NULL) {
    fputs(leitor, file2);
  }
}

Filing cabinet main.c:

#include <stdio.h>
#include "biblioteca.h"

int main(void)
{
  FILE *file1 = fopen("Arquivo 1.txt", "r");
  if (file1 == NULL) {
    fprintf(stderr, "ERRO ao abrir \"Arquivo 1.txt\"!");
    return 1;
  }

  FILE *file2 = fopen("Arquivo 2.txt", "w");
  if (file2 == NULL) {
    fprintf(stderr, "ERRO ao abrir \"Arquivo 2.txt\"!");
    return 1;
  }
  copiartxt(file1, file2);

  fclose(file1);
  fclose(file2);

  return 0;
}
  • Your explanation was fantastic. I managed to understand a lot. Thank you very much!!

  • Don’t forget to mark the issue that best served you as accepted (you can change the acceptance later). The best recognition you can give here at Stackoverflow is with the positivity and acceptance of answers. Soon you’ll have enough reputation

  • Can I improve my answer? She has some point where I missed and didn’t notice?

  • Your answer has already satisfied my doubts. I can’t answer you if there’s a mistake or not because I’m a beginner in C, any little mistake goes unnoticed by me.

  • @Gustavopavanati my last message was destined to the one who denied me. If you voted negative it is because my answer can be improved, check?

0

To copy the contents from one file to the other file you can do as you did, using a file . h is to be able to use functions from one file . c in another file or even in . h itself without having the code there, only the header of the function.

For example in your case you might have a file, for example test. c that contains the code for the function copiar_ficheiro() and its file . h that contains the header of the function and for example a main() that executes the code.

test. c

#include <stdio.h>
#include "teste.h"


void copiar_ficheiro(FILE *file1, FILE *file2){
    char leitor[1000];
    while(fgets(leitor, 1000, file1)){
        fprintf(file2,"%s", leitor);
    }

}

test. h

#include <stdio.h>
#include <stdlib.h>

void copiar_ficheiro(FILE *file1, FILE *file2);

int main()
{
    FILE *file1, *file2;

    file1 = fopen("Arquivo 1.txt", "r");
    if (file1 == NULL) {
        printf("Erro\n");
        exit(0);
    }

    file2 = fopen("Arquivo 2.txt", "w");
    if (file2 == NULL) {
        printf("Erro\n");
        exit(0);
    }

    copiar_ficheiro(file1, file2);

    fclose(file1);
    fclose(file2);
    return 0;
}

I hope I’ve cleared your doubt.

  • It wasn’t clear here what the file looks like teste.h. It seems that in it you put code, as the function main

  • I’ll test it here. Plus, thank you very much!!

  • @Jeffersonquesado The . h file is both to define the function header, as being an interface, and that’s what I explained. You can also have a main function that performs these functions or not, depending on the use that each person wants to give you.

  • Reading only your answer, I did not understand that the .h would be just the interface. In the running text, right after test.h, you put two pre-compilation guidelines making inclusion, a forward declaration of the desired function and then the function main. That’s what’s in the structure of your answer, and what I didn’t understand: why did you put implementation in a header file? , further implementation of the main?

Browser other questions tagged

You are not signed in. Login or sign up in order to post.