1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | #include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
/* This is part 1 of a 3-part series of snippets illustrating how to handle
* runtime errors without obscuring the core logic of the function. This
* is the naïve example. It works, but is bad because the code for making
* the newly allocated copy of the error string on the heap is duplicated.
*/
typedef struct {
int x, y, z; // separate lines is preferable, but this is ok for lecture
char name[255]; // do not declare strings like this in production code (security risk)
} ThreeDNamedPoint;
bool write_point(ThreeDNamedPoint p, char* filename, char** a_error) { // 21 lines
// Open file
FILE* fp = fopen("tdnp.bin", "w");
// Error handler #1: Make sure file was opened successfully.
if(fp == NULL) {
const char* temp_error = "cannot open file";
char* error = malloc(sizeof(*error)*(strlen(temp_error) + 1));
strcpy(error, temp_error);
*a_error = error;
return false; // failure
}
// Write object
size_t num_written = fwrite(&p, sizeof(p), 1, fp);
// Error handler #2: Make sure object was written successfully.
if(num_written != 1) {
const char* temp_error = "unable to write to file";
char* error = malloc(sizeof(*error)*(strlen(temp_error) + 1));
strcpy(error, temp_error);
*a_error = error;
fclose(fp);
return false; // failure
}
fclose(fp);
return true;
}
///////////////////////////////////////////////////////////////////////
void _print_point(ThreeDNamedPoint p_orig) {
printf("x=%d, y=%d, z=%d, name=%s\n", p_orig.x, p_orig.y, p_orig.z, p_orig.name);
}
int main(int argc, char* argv[]) {
// Create a ThreeDNamedPoint object
ThreeDNamedPoint p_orig = {.x=5, .y=6, .z=7, .name="polyester"};
// Write the point to a binary file.
char* error = NULL;
write_point(p_orig, "tdnp.bin", &error);
// Handle errors -- if any, print the message and exit
if(error != NULL) {
fprintf(stderr, "Error: %s\n", error);
free(error); // free the memory for the error message
return EXIT_FAILURE;
}
// Read the ThreeDNamedPoint from the binary file created above into a new object.
// It would be better to do this in a separate function, similar to write_point(…).
FILE* fp = fopen("tdnp.bin", "r");
ThreeDNamedPoint p_copy; // not initializing because fread(…) will do that for us
fread(&p_copy, sizeof(p_copy), 1, fp); // essentially copies bytes from disk to memory
fclose(fp);
// Print the original object and the copy made when we read it from disk, to visually
// confirm that they are the same.
_print_point(p_orig);
_print_point(p_copy);
return EXIT_SUCCESS;
}
/* vim: set tabstop=4 shiftwidth=4 fileencoding=utf-8 noexpandtab: */
|
© Copyright 2017 Alexander J. Quinn This content is protected and may not be shared, uploaded, or distributed.