0

There are functions in different files in my C program between which I want to communicate errors. For example: MEMOERY_ALLOCATION_FAILED, FILE_OPENING_FAILED or NAME_NOT_VALID.

I thought of creating an Error linked list like so:

typedef struct Error {
    char *message;
    struct Error *next;
};

And pass this linked list to every function so the functions can add errors if those occur, like so:

int foo(int x, Error *list);

But there is a problem with this one. When allocating space for a new Error, that could fail and the function that called that function could not receive that information.

What are some useful ideas to solve such a problem? Note that I cannot return error codes because:

  1. A function can append more than one error
  2. The functions needs to return other things
5
  • Are you worried about the dynamic allocation of memory for errors, or a lack of memory as a whole?
    – Anon520
    Commented Jul 7 at 2:30
  • 1
    Please explain how/why the program is to continue to execute after some "catastrophic" error has been encountered by a lower level "service" function... If a filename cannot be used, it cannot be used; if too many files are open, too many are open; if allocation fails, then allocation fails... C functions return 1 "thing". Me thinks your overall design needs to be changed to work as C programs have worked for over 50 years.
    – Fe2O3
    Commented Jul 7 at 2:51
  • @talopl, How is list assigned/initialized prior to the first foo() call? Commented Jul 7 at 3:26
  • @talopl look at my example, maybe that's what you need?
    – Ihdina
    Commented Jul 7 at 7:21
  • @Anon520 about dynamic allocation for memory as errors. Because if it fails, I can't communicate the error between the two functions
    – talopl
    Commented Jul 7 at 8:24

2 Answers 2

1

But there is a problem with this one. When allocating space for a new Error, that could fail and the function that called that function could not receive that information.

If you're worried about the dynamic allocation of memory for errors you could try pre-allocating arrays of error structures and pre-allocating a fixed size of memory for error messages.

However, as another user mentioned, why would the program continue after a large error has occurred? At that point it's usually better to simply have the function return an error value, rather than try to continue execution.

2
  • I need to find all errors without exiting the program, and for example, when I have finished reading a file, log them. I doesn't necessarily have to be a C error. It can also be an error in the file I am reading such as NUMBER_TOO_LARGE.
    – talopl
    Commented Jul 7 at 8:21
  • @talopl Understood. In that case I'd recommend preallocating memory so that you have space to save the errors if you do run out.
    – Anon520
    Commented Jul 7 at 11:11
0
/******************************************************************************

                            Online C Compiler.
                Code, Compile, Run and Debug C program online.
Write your code in this editor and press "Run" button to compile and execute it.

*******************************************************************************/

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

// Define the Error structure
typedef struct Error {
    int errorCode;
    char errorMessage[100];
    struct Error *next;
} Error;

// Function to create a new Error node
Error* createError(int code, const char* message) {
    Error *newError = (Error*)malloc(sizeof(Error));
    if (newError == NULL) {
        fprintf(stderr, "Memory allocation failed.\n");
        exit(EXIT_FAILURE);
    }
    newError->errorCode = code;
    strncpy(newError->errorMessage, message, sizeof(newError->errorMessage));
    newError->next = NULL;
    return newError;
}

// Function to insert an Error node at the beginning of the list
void insertError(Error **head, int code, const char* message) {
    Error *newError = createError(code, message);
    newError->next = *head;
    *head = newError;
}

// Function to print all Errors in the linked list
void printErrors(Error *head) {
    Error *current = head;
    while (current != NULL) {
        printf("Error Code: %d, Message: %s\n", current->errorCode, current->errorMessage);
        current = current->next;
    }
}

// Function to free the entire linked list
void freeErrors(Error *head) {
    Error *current = head;
    while (current != NULL) {
        Error *temp = current;
        current = current->next;
        free(temp);
    }
}


// Define a struct to hold the result and error information
struct DoubleResult {
    double value;  // Result
    Error *error;  // Error 
};

struct DoubleResult divide(double a, double b, Error *head) {
    struct DoubleResult result;

    if (a >= INT_MAX) {
        // catch first error
        insertError(&head, 100, "Value a is overflow");
    }
    if (b == 0) {
        // catch second error
        insertError(&head, 101, "Division by zero");
    }
    if (a >= INT_MAX || b == 0) {
        // errors
        result.error = head;
        result.value = -1; // default if error
        return result;
    }

    // success
    result.error = NULL;  // default if success
    result.value = a/b;
    return result;
}


int main() {
    Error *head = NULL;

    // example 1
    printf("divide(INT_MAX, 0)\n");
    struct DoubleResult result1 = divide(INT_MAX, 0, head);
    if(result1.error == NULL) {
        // success
        printf("result %.f\n", result1.value);
    }
    else {
        // error
        printErrors(result1.error);
    }

    printf("\n");


    // example 2
    printf("divide(10, 2)\n");
    struct DoubleResult result2 = divide(10, 2, head);
    if(result2.error == NULL) {
        // success
        printf("result %.f\n", result2.value);
    }
    else {
        // error
        printErrors(result2.error);
    }

    
    // Free the allocated memory
    freeErrors(head);

    return 0;
}
    

Result:

divide(INT_MAX, 0)
Error Code: 101, Message: Division by zero
Error Code: 100, Message: Value a is overflow

divide(10, 2)
result 5

Not the answer you're looking for? Browse other questions tagged or ask your own question.