📄 util.c
字号:
#include <string.h>#include <stdio.h>#include <stdlib.h>#include "util.h"/* This file contains utility functions widely used in * * my programs. Many are simply versions of file and * * memory grabbing routines that take the same * * arguments as the standard library ones, but exit * * the program if they find an error condition. */int linenum; /* Line in file being parsed. */FILE *my_fopen (char *fname, char *flag, int prompt) { FILE *fp; /* prompt = 1: prompt user. prompt=0: use fname */ while (1) { if (prompt) scanf("%s",fname); if ((fp = fopen(fname,flag)) != NULL) break; printf("Error opening file %s for %s access.\n",fname,flag); if (!prompt) exit(1); printf("Please enter another filename.\n"); } return (fp);}int my_atoi (const char *str) {/* Returns the integer represented by the first part of the character * * string. Unlike the normal atoi, I return -1 if the string doesn't * * start with a numeric digit. */ if (str[0] < '0' || str[0] > '9') return (-1); return (atoi(str));}void *my_calloc (size_t nelem, size_t size) { void *ret; if ((ret = calloc (nelem,size)) == NULL) { fprintf(stderr,"Error: Unable to calloc memory. Aborting.\n"); exit (1); } return (ret);}void *my_malloc (size_t size) { void *ret; if ((ret = malloc (size)) == NULL) { fprintf(stderr,"Error: Unable to malloc memory. Aborting.\n"); abort (); exit (1); } return (ret);}void *my_realloc (void *ptr, size_t size) { void *ret; if ((ret = realloc (ptr,size)) == NULL) { fprintf(stderr,"Error: Unable to realloc memory. Aborting.\n"); exit (1); } return (ret);}void *my_chunk_malloc (size_t size, struct s_linked_vptr **chunk_ptr_head, int *mem_avail_ptr, char **next_mem_loc_ptr) { /* This routine should be used for allocating fairly small data * * structures where memory-efficiency is crucial. This routine allocates * * large "chunks" of data, and parcels them out as requested. Whenever * * it mallocs a new chunk it adds it to the linked list pointed to by * * chunk_ptr_head. This list can be used to free the chunked memory. * * If chunk_ptr_head is NULL, no list of chunked memory blocks will be kept * * -- this is useful for data structures that you never intend to free as * * it means you don't have to keep track of the linked lists. * * Information about the currently open "chunk" must be stored by the * * user program. mem_avail_ptr points to an int storing how many bytes are * * left in the current chunk, while next_mem_loc_ptr is the address of a * * pointer to the next free bytes in the chunk. To start a new chunk, * * simply set *mem_avail_ptr = 0. Each independent set of data structures * * should use a new chunk. */ /* To make sure the memory passed back is properly aligned, I must * * only send back chunks in multiples of the worst-case alignment * * restriction of the machine. On most machines this should be * * a long, but on 64-bit machines it might be a long long or a * * double. Change the typedef below if this is the case. */ typedef long Align;#define CHUNK_SIZE 32768#define FRAGMENT_THRESHOLD 100 char *tmp_ptr; int aligned_size; if (*mem_avail_ptr < size) { /* Need to malloc more memory. */ if (size > CHUNK_SIZE) { /* Too big, use standard routine. */ tmp_ptr = my_malloc (size);/*#ifdef DEBUG printf("NB: my_chunk_malloc got a request for %d bytes.\n", size); printf("You should consider using my_malloc for such big requests.\n");#endif */ if (chunk_ptr_head != NULL) *chunk_ptr_head = insert_in_vptr_list (*chunk_ptr_head, tmp_ptr); return (tmp_ptr); } if (*mem_avail_ptr < FRAGMENT_THRESHOLD) { /* Only a small scrap left. */ *next_mem_loc_ptr = my_malloc (CHUNK_SIZE); *mem_avail_ptr = CHUNK_SIZE; if (chunk_ptr_head != NULL) *chunk_ptr_head = insert_in_vptr_list (*chunk_ptr_head, *next_mem_loc_ptr); }/* Execute else clause only when the chunk we want is pretty big, * * and would leave too big an unused fragment. Then we use malloc * * to allocate normally. */ else { tmp_ptr = my_malloc (size); if (chunk_ptr_head != NULL) *chunk_ptr_head = insert_in_vptr_list (*chunk_ptr_head, tmp_ptr); return (tmp_ptr); } }/* Find the smallest distance to advance the memory pointer and keep * * everything aligned. */ if (size % sizeof (Align) == 0) { aligned_size = size; } else { aligned_size = size + sizeof(Align) - size % sizeof(Align); } tmp_ptr = *next_mem_loc_ptr; *next_mem_loc_ptr += aligned_size; *mem_avail_ptr -= aligned_size; return (tmp_ptr);}void free_chunk_memory (struct s_linked_vptr *chunk_ptr_head) {/* Frees the memory allocated by a sequence of calls to my_chunk_malloc. */ struct s_linked_vptr *curr_ptr, *prev_ptr; curr_ptr = chunk_ptr_head; while (curr_ptr != NULL) { free (curr_ptr->data_vptr); /* Free memory "chunk". */ prev_ptr = curr_ptr; curr_ptr = curr_ptr->next; free (prev_ptr); /* Free memory used to track "chunk". */ }}struct s_linked_vptr *insert_in_vptr_list (struct s_linked_vptr *head, void *vptr_to_add) {/* Inserts a new element at the head of a linked list of void pointers. * * Returns the new head of the list. */ struct s_linked_vptr *linked_vptr; linked_vptr = (struct s_linked_vptr *) my_malloc (sizeof(struct s_linked_vptr)); linked_vptr->data_vptr = vptr_to_add; linked_vptr->next = head; return (linked_vptr); /* New head of the list */}t_linked_int *insert_in_int_list (t_linked_int *head, int data, t_linked_int ** free_list_head_ptr) {/* Inserts a new element at the head of a linked list of integers. Returns * * the new head of the list. One argument is the address of the head of * * a list of free ilist elements. If there are any elements on this free * * list, the new element is taken from it. Otherwise a new one is malloced. */ t_linked_int *linked_int; if (*free_list_head_ptr != NULL) { linked_int = *free_list_head_ptr; *free_list_head_ptr = linked_int->next; } else { linked_int = (t_linked_int *) my_malloc (sizeof (t_linked_int)); } linked_int->data = data; linked_int->next = head; return (linked_int);}void free_int_list (t_linked_int **int_list_head_ptr) { /* This routine truly frees (calls free) all the integer list elements * * on the linked list pointed to by *head, and sets head = NULL. */ t_linked_int *linked_int, *next_linked_int; linked_int = *int_list_head_ptr; while (linked_int != NULL) { next_linked_int = linked_int->next; free (linked_int); linked_int = next_linked_int; } *int_list_head_ptr = NULL; } void alloc_ivector_and_copy_int_list (t_linked_int **list_head_ptr, int num_items, struct s_ivec *ivec, t_linked_int **free_list_head_ptr) {/* Allocates an integer vector with num_items elements and copies the * * integers from the list pointed to by list_head (of which there must be * * num_items) over to it. The int_list is then put on the free list, and * * the list_head_ptr is set to NULL. */ t_linked_int *linked_int, *list_head; int i, *list; list_head = *list_head_ptr; if (num_items == 0) { /* Empty list. */ ivec->nelem = 0; ivec->list = NULL; if (list_head != NULL) { printf ("Error in alloc_ivector_and_copy_int_list:\n Copied %d " "elements, but list at %p contains more.\n", num_items, list_head); exit (1); } return; } ivec->nelem = num_items; list = (int *) my_malloc (num_items * sizeof (int)); ivec->list = list; linked_int = list_head; for (i=0;i<num_items-1;i++) { list[i] = linked_int->data; linked_int = linked_int->next; } list[num_items-1] = linked_int->data;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -