简体   繁体   中英

C program that stops running due to a function be called?

this might be difficult to explain. I am working on a program that takes in a file with numbers in it. the first two numbers are the dimensions of a matrix rows and then columns. the rest of the numbers are the elements of the matrix. what I am having trouble with is that after I created a function to read in a number in a give c style string, the program stops doing anything. It compiles and runs but nothing is ever done, not even printing the first line after main.

proj2.c

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

float readNum(char* buffer, int *pos);

int main(){


    char buffer[512];

    printf("Enter File Name: ");
    //char* fileName = fgets(buffer, sizeof(buffer), stdin);
    FILE* file = fopen("matrix.txt", "r");
    if(file == NULL){
        printf("ERROR COULD NOT OPEN FILE\n");
        exit(1);

    }
    int row = 0;
    int col = 0;
    int rowcheck = 0;
    int colcheck = 0;
    int matrixcheck = 0;
    while(!feof(file)){
        printf("HELLO");

        if(fgets(buffer,sizeof(buffer),file) != NULL){
            //position of current character
            int pos = 0;

            //current character
            char current;

            //loop to determine the dimensions of the matrix
            if(colcheck == 0 && rowcheck == 0){
                while(colcheck == 0 || rowcheck == 0){
                    //set current character
                    current = buffer[pos];
                    //determine if current character is a number and that the nex character is a space
                    //for single digit row dimensions
                    if(current >= '0' && current <= '9'  && buffer[pos+1] == ' ' && rowcheck == 0){
                        row += current - '0';
                        rowcheck = 1;
                    }
                    //if not single digit row dimension add the current character times 10
                    //and repeat loop to obtain the second digit
                    else if (buffer[pos+1] >= '0' && buffer[pos+1] <= '9' && rowcheck == 0){
                        row += (current - '0') * 10;
                    }
                    //for columns check if current character is a number and if the next character is space or newline
                    //and that row has already been checked
                    else if(current >= '0' && current <= '9' && (buffer[pos+1] == ' ' || buffer[pos+1] == 10) && rowcheck == 1){
                        col += current - '0';
                        colcheck = 1;
                    }
                    //final check for if columns is double digit so check if next char is a number and that current char is
                    //not a space
                    else if(buffer[pos] != ' ' && buffer[pos+1] >= '0' && buffer[pos+1] <= '9' && rowcheck == 1){
                        col += (current - '0' ) * 10;
                    }
                    pos++;
                    printf("rows: %d  cols: %d", row,col);
                }
            }
            //condition to ensure columns and rows have been determined
            else if(colcheck == 1 && rowcheck == 1){
                //loop to find the elements of the matrix
                while(matrixcheck == 0){
                    current = buffer[pos];
                    if(buffer[pos + 1] != 10){
                        if((current >= '0' && current <= '9') || current == '-' || current == '.'){
                            float num = readNum(buffer, &pos);
                            printf("number: %f", num);
                        }
                    }
                }

            }
        }
    }
    fclose(file);
}

and readNum.c

#include <stdio.h>
#include <math.h>

float readNum(char* buffer,int *pos){
    int negative = 1;
    int y = 0;
    float number = 0;
    if(buffer[*pos] == '-'){
        negative = -1;
        (*pos)++;
    }
    while(buffer[*pos + y] >= '0' && buffer[*pos + y] <= '9'){
        y++;
    }
    for(int z = 0; z < y; z++){
        number += (buffer[*pos + z] - 48) * pow(10, y - z - 1);
    }
    *pos += y;
    if(buffer[*pos] == '.'){
        (*pos)++;
        int d = 0;
        while(buffer[*pos + d] >= '0' && buffer[*pos + d] <= '9'){
            if(buffer[d + *pos] == '.'){
                printf("ERROR: multiple decimals in an element");
            }
            d++;
        }
        for(int z = 0; z < d; z++){
            number += (buffer[z + *pos] - '0') * pow(10, -z - 1);
        }
        pos += d;
    }
    return number * negative;
}

commenting out the lines

float num = readNum(buffer, &pos);
printf("number: %f", num);

allows the program to run normally, but uncommenting them it just stops doing anything, in eclipse the console just stays blank running something or other and I terminate it after a bit because nothing is happening, not even the first line is being printed.

this is a sample file that is being read 3 2 56 12 98 25 34.5 45

Thank you in advance

SOLUTION has been found, i'm not sure if everyone understood what exactly is happening in the program. main would not run at all, the first line would not print anything. the solution to this was using fflush(stdout) after the first print statement.

Parsing the file character by character is way to complicated when you are trying to read floats. Use the function provided by the standard library.

Your code can yield undefined behaviour, because you don't check the boundaries of buffer , for example:

if(current >= '0' && current <= '9'  && buffer[pos+1] == ' ' && rowcheck == 0){
    row += current - '0';
    rowcheck = 1;
}

You never check if your read the '\\0' -terminating byte and keep incrementing pos , buffer[pos+1] might access beyond the limit. Also I don't understand how you are really parsing the dimensions. That's why I tell you, don't reinvent the wheel, use the tools at your disposal.

You say that the dimensions are in the first line, then you can get the dimension by doing this:

char buffer[512];
if(fgets(buffer, sizeof buffer, file) == NULL)
{
    fprintf(stderr, "File is empty\n");
    flcose(file);
    return 1;
}

size_t cols,rows;

if(fscanf("%zu %zu", &rows, &cols) != 2)
{
    fprintf(stderr, "Invalid file format, cannot get columns and rows\n");
    fclose(file);
    return 1;
}

if(rows == 0 || cols == 0)
{
    fprintf(stderr, "Invalid dimension %zux%zu\n", rows, cols);
    fclose(file);
    return 1;
}

Now, you can parse the file like this:

float matrix[rows][cols] = { 0 };

for(size_t i = 0; i < rows; ++i)
{
    if(fgets(buffer, sizeof buffer, file) == NULL)
    {
        fprintf(stderr, "End of file reached before filling matrix\n");
        fclose(file);
        return 1;
    }

    int pos;
    char *scan = buffer;

    for(size_t j = 0; j < cols; ++j)
    {
        if(sscanf(scan, "%f%n", matrix[i] + j, &pos) != 1)
        {
            fprintf(stderr, "Invalid format at line %zu\n", i+2);
            break; // continue parsing with the next line
        }

        scan += pos;
    }
}

fclose(file);

printf("matrix[%zu][%zu] = %f\n", rows/2, cols/2, matrix[rows/2][cols/row]);

This code is more robust, because it checks if the functions are working as intended. If no more lines can be read before the the matrix is filled, then you can return an error message and end the program. If the lines don't have the proper format, I ignore that line and the row is filled with 0 while also printing an error message. If there are more lines than rows, they are ignored and you would not overflow the buffers. The intentions are also more clear and it's easier to understand what I'm doing.

Like I said at the beginning, using the function provided by the standard C library is better than trying to invent the wheel again. Your code is complicated and hard to read.

Also see why is while(feof) always wrong . It's easier to manage the end of file when using fgets , because fgets returns NULL when no more data can be read, either because of an I/O error or because the file reached EOF. That's why my example above always checks the return value of fgets . Note how I use %n in the scanf format: %n returns the number of characters consumed thus far from the input, which is a great info when using sscanf in a loop. I also check if scanf doesn't return the number of matched elements (note that %n does not increase the number of matched elements). For more information about this see the documentation of scanf .

This loop can run forever:

while(buffer[*pos] >= '0' && buffer[*pos] <= '9'){
            y++;
}

How can we get out of this loop?:

        while(matrixcheck == 0){
            current = buffer[pos];
            if(buffer[pos + 1] != 10){
                if((current >= '0' && current <= '9') || current == '-' || current == '.'){
                    float num = readNum(buffer, &pos);
                    printf("number: %f", num);
                }
            }
        }

SOLUTION has been found, i'm not sure if everyone understood what exactly is happening in the program. main would not run at all, the first line would not print anything. the solution to this was using fflush(stdout) after the first print statement.

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