Writing my own Cat function in C

Vzqivan picture Vzqivan · May 6, 2015 · Viewed 12.4k times · Source

Hi i don't know how to simulate my own Cat function in C, i know how it works when no arguments are set and i already get it, but my problem is when i tried to open a file and then print itself...

my code until now:

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

int main(int argc, char* argv[])
{  
    char *a1 = (char*) malloc (sizeof(char));
    int sz, fd,cont=0, cont1=0;
    char *b1 = (char*) malloc (sizeof(char));
    //char *a2 = (char*) malloc (sizeof(char));
    char * a2;
    char *b2 = (char*) malloc (sizeof(char));

    // NO PARAMETERS
    while (argc == 1){      
        sz=read(0, a1, 1);
        b1[cont]=a1[0];

        if(b1[cont]=='\n'){
            write(1,b1,cont);
            write(1,"\n",1);
            b1=NULL;            
        }

        cont=cont+1;
        b1=(char*) realloc(b1, sizeof(char)*cont);
      }

    // 1 PARAMETER (FILE)   /*Here is the problem*/
    if (argc > 1){

        fd=open(argv[1],O_RDONLY);
        a2=fgetc(fd);

        while (a2 != EOF){
            b2[cont1]=a2;
            cont1=cont1+1;
            b2=(char*) realloc (b2, sizeof(char)*cont1+1);
            a2=fgetc(fd);
        }

        write(1,b2,cont);
        b2=NULL;
        close(fd);  
    }

    return 0;
}

What am i supposed to do ?

Answer

Jonathan Leffler picture Jonathan Leffler · May 6, 2015

If you are using open() and close(), you cannot use fgetc(). You need to use fopen() and fclose() to be able to use fgetc().

Either way, you need a function which can be called with either the standard input (spelled 0 or stdin) or with the file that was opened (fd or fp are conventional names for 'file descriptor' and 'file pointer'). You can specify the output stream too. Hence, for example, the interfaces:

int cat_fd(int ifd, int ofd);
int cat_fp(FILE *ifp, FILE *ofp);

Your main program then calls your chosen function with the standard input and standard output or with the opened file and standard output.


Additionally, you have:

char *a1 = (char*) malloc (sizeof(char));

Ignoring the cast, this is an expensive way of writing:

char a1[1];

Your loops are reading a single character at a time. This is OK with the file streams from <stdio.h>, but is bad for performance if you're using file descriptors. You should be reading block of, say, 4096 characters at a time.

int cat_fd(int ifd, int ofd)
{
    char buffer[4096];
    ssize_t nbytes;
    while ((nbytes = read(ifd, buffer, sizeof(buffer))) > 0)
    {
        if (write(ofd, buffer, nbytes) != nbytes)
            return -1;
    }
    return (nbytes < 0) ? -1 : 0;
}

You don't need the dynamic memory allocation; it is only confusing you and wasting time in the program. The code in the main() function then looks more like:

if (argc == 1)
{
    if (cat_fd(0, 1) != 0)
        fprintf(stderr, "failed to copy standard input\n");
}
else
{
    for (int i = 1; i < argc; i++)
    {
        int fd = open(argv[i], O_RDONLY);
        if (fd < 0)
            fprintf(stderr, "failed to open %s for reading\n", argv[i]);
        else
        {
            if (cat_fd(fd, 1) != 0)
                fprintf(stderr, "failed to copy %d to standard output\n", argv[i]);
            close(fd);
        }
    }
}

Rewriting to use cat_fp() is an exercise for the reader. You might find Tried and true simple file copying code in C relevant.