Новые книги

Фризен Ирина Григорьевна – кандидат педагогических наук, преподаватель информационных технологий, автор многочисленных работ в сфере информационных технологий.

Настоящее учебное пособие написано в соответствии с государственной программой изучения дисциплины для средних специальных учебных заведений по специальности 230103 «Автоматизированные системы обработки информации и управления».

Офисное программирование

В пособии дается достаточный материал для проведения практических занятий по дисциплине, а также основной теоретический материал, необходимый при изучении того или иного вопроса. На основе предлагаемого материала можно строить проведение различных видов занятий.

Учебное пособие ставит перед собой цель помочь студентам изучить данную дисциплину в полном объеме, отвечающем требованиям государственного стандарта по дисциплине.

Предназначается для преподавателей и студентов средних специальных учебных заведений, а также может быть использовано студентами высших учебных заведений, изучающих данную дисциплину.

В учебном пособии рассматривается более 60 задач, сопровождаемых 130 рисунками и подробными объяснениями.
Книга будет интересна представителям любых стартапов, руководителям среднего звена, которые решили стать независимыми консультантами и экспертами. Рекламным агентствам она поможет в оптимизации внутренних процессов и воспитании проектных менеджеров в штате. Сотрудникам HR-отделов, рекрутерам и охотникам за головами книга пригодится при поиске редких специалистов с ценными навыками. Фрилансерам книга расширит кругозор, представляя репортаж с другой стороны баррикад.

Примеры.

Пример 11

/* Пакет для ловли наездов областей выделенной памяти
 * друг на друга,
 * а также просто повреждений динамически отведенной памяти.
 */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>      /* O_RDWR */
#include <sys/types.h>
#include <ctype.h>
#include <locale.h>
#define CHECKALL
/*
	----------------- <--------- ptr
	| red_zone      | головная "пограничная зона"
	----------------	| byte[0]       |
	|     ...       |
	| byte[size-1]  |
	| placeholder   |
	----------------- выровнено на границу RedZoneType
	| red_zone      | хвостовая "пограничная зона"
	----------------
Основные идеи состоят в следующем:
1) Перед и после области данных строится зона,
   заполненная заранее известным "узором".
   Если ее содержимое изменилось, испорчено    значит мы где-то разрушили нашу память.
2) Ведется таблица всех отведенных malloc()-ом сегментов памяти;
   для экономии места эта таблица вынесена в файл (но зато это
   очень медленно).
3) Мы не можем пользоваться библиотекой STDIO для обменов с файлом,
   потому что эта библиотека сама использует malloc() и буфера
   могут быть разрушены.
*/
typedef char *RedZoneType;      /* выравнивание на границу указателя */
/* Можно выравнивать на границу double:
typedef double RedZoneType;
 */
/* Сегмент, выделяемый в оперативной памяти */
typedef struct _allocFrame {
	RedZoneType red_zone;   /* головная "пограничная зона"            */
	RedZoneType stuff[1];   /* место для данных                       */
				/* хвостовая "пограничная зона" безымянна */
} AllocFrame;
const int RedZoneTypeSize = sizeof(RedZoneType);
/* Запись, помещаемая в таблицу всех выделенных malloc()ом
 * областей памяти.
 */
typedef struct _memFileRecord {
	AllocFrame *ptr;        /* адрес                                 */
	size_t size, adjsize;   /* размер выделенной области             */
				/* (0,0) - означает "сегмент освобожден" */
	int serial;
} MemFileRecord;
char red_table[] = {
	0x01, 0x03, 0x02, 0x04,
	0x11, 0x13, 0x12, 0x14,
	0x21, 0x23, 0x22, 0x24,
	0x31, 0x33, 0x32, 0x34
};
char free_table[] = {
	'F', 'r', 'e', 'e', 'p', 't', 'r', '\0',
	'F', 'r', 'e', 'e', 'p', 't', 'r', '\0'
};
/* Файл для хранения таблицы указателей */
static  int mem_fd = (-1);
#define PTABLE "PointerTable.bin"
#define NRECORDS 256
MemFileRecord memrecords[NRECORDS];
/* ============================================================= */
void  MEMputTableRecord(AllocFrame *newptr, AllocFrame *oldptr,
			size_t size, size_t adjsize);
void  MEMputTableRecordKilled(AllocFrame *ptr);
void  MEMerasePreviousRecords(AllocFrame *ptr);
int   MEMcheckRecord(MemFileRecord *rec);
int   MEMcheck_consistency(AllocFrame *ptr);
void  MEMmakeRedZones(char *cptr, size_t size, size_t adjsize);
void  MEMopenFd();
/* ============================================================= */
/* Этим следует пользоваться вместо стандартных функций          */
void *MEMmalloc (size_t size);
void *MEMrealloc(void *ptr, size_t size);
void *MEMcalloc (size_t n,  size_t size);
void  MEMfree   (void *ptr);
void  MEMcheckAll();  /* это можно вызывать в середине программы */
/* ============================================================= */
void MEMopenFd(){
	if(mem_fd < 0){
		close(creat(PTABLE, 0644));     /* создать файл */
		mem_fd = open(PTABLE, O_RDWR);  /* чтение+запись */
		unlink(PTABLE);                 /* только для M_UNIX */
		atexit(MEMcheckAll);
		setlocale(LC_ALL, "");
	}
}
/* Поместить запись в таблицу всех указателей на
 * выделенные области памяти.
 */
void MEMputTableRecord(AllocFrame *newptr, /* для записи */
		       AllocFrame *oldptr, /* для стирания */
		       size_t size,        /* размер данных */
		       size_t adjsize      /* размер всей записи с зонами */
){
	MemFileRecord memrecord;
	static int serial = 0;
	memrecord.ptr     = newptr;
	memrecord.size    = size;
	memrecord.adjsize = adjsize;
	memrecord.serial  = serial++;
	MEMopenFd();
#ifdef CHECKALL
	/* стереть прежние записи про этот адрес */
	MEMerasePreviousRecords(oldptr);
#endif
	lseek(mem_fd, 0L, SEEK_END);                    /* в конец */
	write(mem_fd, &memrecord, sizeof memrecord);    /* добавить */
}
/* Сделать запись об уничтожении области памяти */
void  MEMputTableRecordKilled(AllocFrame *ptr){
	/* Пометить как size=0, adjsize=0 */
	MEMputTableRecord(ptr, ptr, 0, 0);
}
/* Коды ответа функции проверки */
#define OK      0       /* все хорошо                 */
#define DAMAGED 1       /* повреждена "погранзона"    */
#define FREED   2       /* эта память уже освобождена */
#define NOTHERE (-1)    /* нет в таблице              */
/* Проверить сохранность "пограничных зон" */
int MEMcheckRecord(MemFileRecord *rec){
	int code = OK;
	char *cptr;
	register i;
	AllocFrame *ptr        = rec->ptr;
	size_t size            = rec->size;
	size_t adjsize         = rec->adjsize;
	if(size == 0 && adjsize == 0){
		printf("%p [%p] -- сегмент уже освобожден, "
		       "record=#%d.\n",
			&ptr->stuff[0], ptr,
			rec->serial
		);
		return FREED;
	}
	cptr    = (char *) ptr;
	for(i=0; i < adjsize; i++){
	    if(i <  RedZoneTypeSize || i >= RedZoneTypeSize + size ){
		/* головная погранзона ИЛИ хвостовая погранзона */
		if( cptr[i] != red_table[ i % RedZoneTypeSize ] ){
		   printf("%p [%p] -- испорчен байт %4d [%4d]"
			  "= 0x%02X '%c' record=#%d size=%lu.\n",
			   &ptr->stuff[0], ptr,
			   i - RedZoneTypeSize, i,
			   cptr[i] & 0xFF,
			   isprint(cptr[i] & 0xFF) ? cptr[i] & 0xFF : '?',
			   rec->serial, size
		   );
		   code = DAMAGED;
		}
	    }
	}
	for(i=0; i < RedZoneTypeSize; i++)
		if(cptr[i] == free_table[i]){
			printf("%p -- уже освобождено?\n", ptr);
			code = FREED;
		}
	if(code != OK) putchar('\n');
	return code;
}
/* Проверить сохранность памяти по указателю ptr. */
int MEMcheck_consistency(AllocFrame *ptr){
	MemFileRecord mr_found;
	int nrecords, i, found = 0;
	size_t size;
	MEMopenFd();
	/* Ищем запись в таблице указателей */
	lseek(mem_fd, 0L, SEEK_SET);    /* перемотать в начало */
	for(;;){
		size = read(mem_fd, memrecords, sizeof memrecords);
		nrecords = size / sizeof(memrecords[0]);
		if(nrecords <= 0) break;
		for(i=0; i < nrecords; i++)
			if(memrecords[i].ptr == ptr){
			/* Мы ищем последнюю запись про память
			 * с таким адресом, поэтому
			 * вынуждены прочитать ВЕСЬ файл.
			 */
				mr_found = memrecords[i];
				found++;
			}
	}
	if(found) {
		return MEMcheckRecord(&mr_found);
	} else {
		printf("%p -- запись в таблице отсутствует.\n", ptr);
		return NOTHERE;
	}
}
/* Уничтожить все прежние записи про ptr, прописывая их adjsize=0 */
void MEMerasePreviousRecords(AllocFrame *ptr){
	int nrecords, i, found;
	size_t size;
	MEMopenFd();
	lseek(mem_fd, 0L, SEEK_SET);    /* перемотать в начало */
	for(;;){
		found = 0;
		size = read(mem_fd, memrecords, sizeof memrecords);
		nrecords = size / sizeof(memrecords[0]);
		if(nrecords <= 0) break;
		for(i=0; i < nrecords; i++)
			if(memrecords[i].ptr == ptr){
				memrecords[i].adjsize = 0;
				/* memrecords[i].size = 0; */
				found++;
			}
		if(found){
			lseek(mem_fd, -size, SEEK_CUR);    /* шаг назад */
			write(mem_fd, memrecords, size);   /* перезаписать */
		}
	}
}
void MEMcheckAll(){
#ifdef CHECKALL
	int nrecords, i;
	size_t size;
	printf("Проверка всех указателей -------------\n");
	MEMopenFd();
	lseek(mem_fd, 0L, SEEK_SET);    /* перемотать в начало */
	for(;;){
		size = read(mem_fd, memrecords, sizeof memrecords);
		nrecords = size / sizeof(memrecords[0]);
		if(nrecords <= 0) break;
		for(i=0; i < nrecords; i++)
			if(memrecords[i].adjsize != 0)
				MEMcheckRecord(&memrecords[i]);
	}
	printf("Проверка всех указателей завершена ---\n");
#endif
}
/* ============================================================= */
/* Заполнение пограничных зон образцом - "следовой дорожкой" */
void MEMmakeRedZones(char *cptr, size_t size, size_t adjsize){
	register i;
	for(i=0; i < adjsize; i++){
		if(i <  RedZoneTypeSize || i >= RedZoneTypeSize + size ){
		   /* головная погранзона ИЛИ
		    * хвостовая погранзона + дополнение
		    * до целого числа RedZoneType-ов
		    */
			cptr[i] = red_table[ i % RedZoneTypeSize ];
		}
	}
}
/* ============================================================= */
/* Функция выделения памяти */
void *MEMmalloc(size_t size){
	AllocFrame *retptr;
	int fullRedZoneTypes =
		(size + RedZoneTypeSize - 1) / RedZoneTypeSize;
	size_t adjustedSize =
		sizeof(retptr->red_zone) * 2 + /* две погранзоны */
		fullRedZoneTypes * RedZoneTypeSize;
	retptr  = (AllocFrame *) malloc(adjustedSize);
	if(retptr == NULL) return NULL;
	MEMmakeRedZones ((char *) retptr, size, adjustedSize);
	MEMputTableRecord(retptr, retptr, size, adjustedSize);
	return &retptr->stuff[0];
	/* вернуть указатель на зону данных */
}
void *MEMrealloc(void *ptr, size_t size){
	AllocFrame *retptr;
	char *cptr = (char *)ptr - RedZoneTypeSize;  /* прежний AllocFrame */
	AllocFrame *oldptr = (AllocFrame *) cptr;
	int fullRedZoneTypes =
		(size + RedZoneTypeSize - 1) / RedZoneTypeSize;
	size_t adjustedSize =
		sizeof(retptr->red_zone) * 2 +
		fullRedZoneTypes * RedZoneTypeSize;
	/* Проверить сохранность того, что мы сейчас будем realloc-ить */
	MEMcheck_consistency(oldptr);
	retptr  = (AllocFrame *) realloc((void *)oldptr, adjustedSize);
	if(retptr == NULL) return NULL;
	MEMmakeRedZones ((char *) retptr, size, adjustedSize);
	MEMputTableRecord(retptr, oldptr, size, adjustedSize);
	return &retptr->stuff[0];
}
void *MEMcalloc(size_t n, size_t size){
	size_t newsize = n * size;
	void *ptr = MEMmalloc(newsize);
	memset(ptr, '\0', newsize);
	return ptr;
}
/* Очистка отведенной памяти.
 * ptr - это указатель не на AllocFrame,
 * а на данные - то есть на stuff[0].
 */
void MEMfree(void *ptr){
	char *cptr = (char *)ptr - RedZoneTypeSize;
	int i, code;
	code = MEMcheck_consistency((AllocFrame *) cptr);
	for(i=0; i < RedZoneTypeSize; i++)
		cptr[i] = free_table[i];
	if(code != FREED) free((void *) cptr);
	MEMputTableRecordKilled((AllocFrame *) cptr);
}
/* ============================================================= */
/* Тестовый пример                                               */
/* ============================================================= */
#define MAXPTRS 512
char *testtable[MAXPTRS];
/* Сгенерировать строку случайной длины со случайным содержимым */
char *wildstring(int c){
#define N 1024
	char teststring[N + 1];
	int len, i;
	char *ptr;
	len = rand() % N;
	for(i=0; i < len; i++)
		teststring[i] = c;
	teststring[len] = '\0';
	ptr = (char *) MEMmalloc(len + 1);
	if(ptr){
		strcpy(ptr, teststring);
	} else printf("NULL wildstring()\n");
	return ptr;
}
int main(int ac, char *av[]){
	int ilen, len, n, i;
	srand(time(NULL));
	for(n=0; n < MAXPTRS; n++)
		testtable[n] = wildstring('A');
#define DAMAGE (MAXPTRS/3*2-1)
#ifdef DAMAGE
	/* Навести порчу */
	len = strlen(testtable[DAMAGE]);
	testtable[DAMAGE][len+1] = 'x';
	testtable[DAMAGE][-2]    = 'y';
	printf("ptr=%p len=%d\n", testtable[DAMAGE], len);
#endif
	for(n=0; n < MAXPTRS/2; n++){
		char *p = wildstring('B');
		int length = strlen(p);
		char *ptr;
		i = rand() % MAXPTRS;
		/* Не забыть присвоить возвращенное realloc() значение
		 * обратно в testtable[i] !!!
		 */
		testtable[i] = ptr =
			(char *) MEMrealloc(testtable[i], length + 1);
		if(ptr == NULL) printf("Не могу сделать realloc()\n");
		else            strcpy(ptr, p);
#ifdef DAMAGE
		/* Порча */
		if(n == MAXPTRS/3){
			ptr[length+2] = 'z';
		}
#endif
		MEMfree(p);
	}
	for(n=0; n < MAXPTRS; n++){
		if(testtable[n]) MEMfree(testtable[n]);
	}
#ifdef DAMAGE
	MEMfree(testtable[DAMAGE]);
#endif
	return 0;
}

© Copyright А. Богатырев, 1992-95
Си в UNIX

Назад | Содержание | Вперед