简体   繁体   中英

Reading, a set line range from a file in C

I' am writing a C program which allows the user to dynamically specify the File name from which the data is to be read. Next the user enters a lower bound and an upper bound. The data in the lines from between the bounds is to be printed.

For this the main function makes a call: readValues(cTargetName, iLower, iHiger);

The function readValues is supposed to work as follows:

  1. Check if file exist, if yes. Open it with fopen
  2. Read with feof and fgets line by line the whole file, and store each line in char string
  3. With a for loop, print the correct range of lines from the string

I'm not sure why but the while loop doesn't seem to exit although I use the feof statement, which should terminate after the end of the File is reached.

The code looks as follows:

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

void readValues(char cFileName[75], int n, int m)
{
    //Variable declaration;
    char strArray[50][50];
    char *parser;
    int i = 0;

    FILE *Data;

    if(Data = fopen(cFileName, "rt") == NULL){
        printf("File could not be opened");
        return 1; //Can you return 1 in a void function?
    }

    //Read the file line by line
    while(feof(Data)==0){
        fgets(strArray[i], 200, Data);
        i++;
    }

    //Reading the specified lines
    for(n; n<=m; n++){
        printf("%s", strArray[n]);
    }
}


int main()
{
    char cTargetName[75] = {"C:/Users/User1/Desktop/C_Projects_1/TestData.txt"};
    int iLower = 2;
    int iHiger = 4;

    readValues(cTargetName, iLower, iHiger);

    return 0;
}

All help is appreciated. Thanks in advance!

several issues here, first, you limited the length of lines to 200, not exactly what you might expect to get. the fgets function returns lines up to specified length unless hit by newline character - this should be taken into account. additionally, fgets returns NULL if you hit EOF - no real need to use feof.

second, you could save yourself a lot of pain and simply count the number of times you get a string, and for the times you are within the range just print it immediately. will save you a nice amount of overhead

like this:

#include <stdio.h>
#include <stdlib.h>
#define MAXLINE 200//or anything else you want
void readValues(char cFileName[75], int n, int m)
{
//Variable declaration;
char line[MAXLINE];
int i = 0;

FILE *Data;

if((Data = fopen(cFileName, "rt")) == NULL){
    printf("File could not be opened");
    return 1; //Can you return 1 in a void function?
}

//Read the file line by line and print within range of lines
while((line=fgets(line, MAXLINE,Data))!=NULL){//terminates upon EOF
    if (++i>=n&&i<=m)
        printf(""%s\n",line);
}

}

Here is my solution to your question:

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

#define MIN_LINE_LENGTH 64

typedef enum {
    false, true
} bool;

int main() {

    char filename[PATH_MAX] = {0};
    printf("Enter filename:\n");
    fgets(filename, PATH_MAX, stdin); // get filename from stdin

    char *ptr = filename;

    while (*ptr) { // remove trailing newline at the end of filename (fgets() includes newline)
        if (*ptr == '\n') {
            *ptr = 0;
        }
        ++ptr;
    }

    printf("Enter starting line and end line, separated by a space:\n");

    size_t startLine = 0;
    size_t endLine = 0;

    bool hasFirstNum = false;
    bool hasSecondNum = false;
    bool hasMiddleSpace = false;
    bool hasLastSpace = false;

    size_t numCount = 0;

    int ch;
    while ((ch = fgetc(stdin)) != EOF && ch != '\n') { // continually receive chars from stdin
        if (ch != 32 && !(ch >= 48 && ch <= 57)) { // if not a space or number, raise error
            fprintf(stderr, "Only numerical values (and spaces) can be entered.\n");
            return 1;
        }
        if (ch == 32) {
            if (hasFirstNum) {
                hasMiddleSpace = true;
            }
            if (hasSecondNum) {
                hasLastSpace = true;
            }
            continue;
        }
        else if (!hasFirstNum) {
            ++numCount;
            hasFirstNum = true;
        }
        else if (!hasSecondNum && hasMiddleSpace) {
            ++numCount;
            hasSecondNum = true;
        }
        else if (hasLastSpace) {
            ++numCount;
        }
        if (numCount == 1) {
            startLine *= 10;
            startLine += ch - 48; // '0' character in ASCII is 48
        }
        else if (numCount == 2){
            endLine *= 10;
            endLine += ch - 48;
        }
        else {
            break;
        }
    }

    FILE *fp = fopen(filename, "r");

    if (fp == NULL) {
        fprintf(stderr, "Error opening file.\n");
        return 1;
    }

    char **lines = malloc(sizeof(char *));
    char *line = malloc(MIN_LINE_LENGTH);
    *lines = line;

    int c;

    size_t char_count = 0;
    size_t line_count = 1;

    while ((c = fgetc(fp)) != EOF) { // continually get chars from file stream
        if (c == '\n') { // expand lines pointer if a newline is encountered
            *(line + char_count) = 0;
            ++line_count;
            lines = realloc(lines, line_count*sizeof(char *));
            line = (*(lines + line_count - 1) = malloc(MIN_LINE_LENGTH));
            char_count = 0;
            continue;
        }
        if ((char_count + 1) % MIN_LINE_LENGTH == 0 && char_count != 0) { // expand line pointer if needed
            line = realloc(line, char_count + MIN_LINE_LENGTH);
        }
        *(line + char_count) = c;
        ++char_count;
    }

    if (startLine >= line_count) { // raise error if starting line specified is greater than num. of lines in doc.
        fprintf(stderr, "Specified starting line is less than total lines in document.\n");
        return 1;
    }
    if (endLine >= line_count) { // adjust ending line if it is greater than number of lines in doc.
        endLine = line_count - 1;
    }
    if (startLine == 0) { // we will be using the starting index of 1 as the first line
        startLine = 1;
    }
    
    char **linesPtr = lines + startLine - 1;
    while (startLine++ <= endLine) { // print lines
        printf("%s\n", *linesPtr++);
    }

    for (size_t i = 0; i < line_count - 1; ++i) { // free all memory
        free(*(lines + i));
    }
    free(lines);

    return 0;
}

It is a little more convoluted, but because it uses dynamic memory allocation, it can handle lines of any length within a text file.

If there is anything unclear, please let me know and I would be happy to explain.

Hope this helps!!

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