简体   繁体   中英

How to print characters from text file, using arguments, in C?

I need to set an integer n using an argument -n that will be set as the amount of characters to print from the end of a given .txt file. This needs to be done without the <stdio.h> library as it is a homework piece about system calls.

I have a program that is able to accept the argument -n and prints the amount of characters as specified by the user. It however prints an unreadable list of characters and NULLS after the required output and causes my terminal to malfunction.

#include <sys/types.h> 
#include <fcntl.h> 
#include <stdlib.h>
#include <string.h>

int main(int argc, char* argv[]) 
{ 
    //declaration of variables
    char buf[1000]; 
    int fd;
    int n;

    //initialising n to zero
    n = 0;

    //checking if the program run call is greater than one argument
    if(argc > 1){
    //if the second argument is equal to '-n' then take the 3rd argument (the int) and put it into n using stroll (string to long)
        if(!strncmp(argv[1], "-n", 2)){
    n = atoi(argv[2]);
    }

    //if n has no set value from -n, set it to 200
    if(n == 0){
    n = 200;}

    // open the file for read only 
    fd = open("logfile.txt", O_RDONLY); 
    //Check if it can open and subsequent error handling
    if(fd == -1){
        char err[] = "Could not open the file";
        write(STDERR_FILENO, err, sizeof(err)-1);
        exit(1);
    }

    //use lseek to place pointer n characters from the end of file and then use read to write it to the buffer
    lseek(fd, (n-(2*n)), SEEK_END);
    read(fd, buf, n);

    //write out to the standard output
    write(STDOUT_FILENO, buf, sizeof(buf)-1);

    //close the file fd and exit normally with code 0
    close(fd);
    exit(0);
    return(0);
}

Note: this answer is an adaptation of the original answer to the first version of this question (now on hold)

I need to set an integer n using an argument -n .

Assuming the command line would look similar to prog.exe -n 4 , the arguments of main(int argc, char* argv[]) will be populated as:

argc == 3
argv[] == {"programName.exe", "-n", "4"}

argc could be reduced to 2 by either combining -n and 4 : -n4 , or eliminating the -n altogether, and just recognizing in the code that argv[1] (the 2nd argument) is a string representation of the value you need, and convert it to an int type.

Example:

programName.exe 3

Then code it like this:

int main(int argc, char *argv[])
{
    char *dummy;
    int val;
    if(argc != 2)
    {
        printf("Usage: prog.exe <n> where <n> is a positive integer value.\nProgram will now exit");
        return 0;
    }
    // Resolve value of 2nd argument:
    val = strtol(argv[1], &dummy, 10);
    if (dummy == argv[1] || ((val == LONG_MIN || val == LONG_MAX) && errno == ERANGE))
    {
            //handle error
    }
    //use val to read desired content from file
    ...

    return 0;
}

Some other general suggestions:

User input in general needs to be kept as predictable as possible. Be explicit when requesting what is acceptable for the user to enter, and reject anything that does not comply. Example, if a program is expecting a single digit argument, then force it to be just that, and reject everything else. Given user input that does not comply:

prog.exe 3 4 5

detect in in the code:

int main(int argc, char *argv[]) 
{
    int val = 0;
    char *dummy = NULL;

    if(argc != 2)
    {
        printf("Usage: prog.exe <n> - Where <n> is an integer with value > 0\n Program will now exit.");
        return 0;
    }
    val = strtol(argv[1], &dummy, 10);
    if (dummy == argv[1] || ((val == LONG_MIN || val == LONG_MAX) && errno == ERANGE))
    {
        printf("Usage: prog.exe <n> - Where <n> is an integer with value > 0\n Program will now exit.");
        return 0;

    }

    ...

Using portable functions (replacing lseek with fseek , and open with fopen , etc.) (read this for an example of the reason why ) here is an adaptation of your code that does what you described you needed it to do, including using the prog.exe -n <n> argument, ( argv == 3 ).

int main(int argc, char *argv[])
{
    char *dummy;
    char buf[1000]; 
    int n;    


    //initialising n to zero
    n = 0;

    //checking if the program run call is greater than one argument
    if(argc != 3)
    {
        printf("Usage: prog.exe -n <n> - Where <n> is an integer with value > 0\n Program will now exit.");
       return 0;
    }
    n = strtol(argv[2], &dummy, 10);
    if (dummy == argv[2] || ((n == LONG_MIN || n == LONG_MAX) && errno == ERANGE))
    {
        printf("Usage: prog.exe <n> - Where <n> is an integer with value > 0\n Program will now exit.");
        return 0;

    }


    // open the file for read only 
    FILE *fd = fopen(".\\data.txt", "r");

    //Check if it can open and subsequent error handling
    if(!fd)
    {
        char err[] = "Could not open the file";
        fputs(err, stdout);
        return 0;
    }

    //use lseek to place pointer n characters from the end of file and then use read to write it to the buffer
    fseek(fd, (n-(2*n)), SEEK_END);
    if(fgets(buf, n, fd))
    {
        //write out to the standard output
        fwrite(buf, 1, n, stdout);
    }
    else 
    {
        ;//handle error
    }

    //close the file fd and exit normally with code 0
    fclose(fd);

    return(0);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM