《C和指针》笔记(八)-- 动态内存分配

C/C++ 笔记

QQ : 1841545843
邮箱 : [email protected]

  1. malloc 和 free : malloc从内存池中提取一块合适的内存,并向该程序返回一个指向这块内存的指针。malloc分配的是一块连续的内存,对每个malloc返回的指针都进行检查,确保不是空的,malloc返回一个void*指针。
  2. calloc 在返回指向内存的指针之前把它初始化伟0
  3. realloc 函数用于修改一个已经分配的内存块的大小。
  4. NULL是字面值常量0
  5. malloc分配内存的单位是字节。
pi = malloc(25 * sizeof(int));          // 25个int
  1. 常见的动态内存错误:
  • 对NULL指针进行解引用操作
  • 对分配的内存进行解引用时超过边界
  • 释放本非动态分配的内存,
  • 试图释放动态分配的内存的一部分
  • 一块动态内存释放后任试图继续使用
  1. 定义一个不易发生错误的内存分配器
alloc.h
# include 

# define malloc         don`t use malloc   // 直接调用malloc报错
# define MALLOC(num, type) (type*)alloc((num) * sizeof(type))
extern void* alloc(size_t size);
alloc.c
# include 
# include "alloc.h"
# undef malloc

void* alloc(size_t size)
{
	void* new_mem;
 	// 请求所需的内存,并检查是否分配成功
 	new_mem = malloc(size);
 	if (new_mem == NULL)
 	{
		print("Out of memeory\n");
		exit(1);
	}
	return new_mem;
}
a_client.c
# include "alloc.c"

void function()
{
	int* new_memory;
	new_memary = MALLOC(25, int)
}
  1. 释放一部风内存是不被允许的,但是可以用realloc缩小一块动态内存。
  2. 内存分配实例:
// 排序一列整数值
#include 
#include 

// 函数由qsort调用,用于比较整数值
int compare_integers(void const* a, void const* b)
{
	register int* pa = a;
	register int* pb = b;
	return *pa > *pb ? 1 : *pa < *pb ? -1 : 0;
}

int main ()
{
	int* array;
	int n_values;
	int i;
	
	// 观察共有多个值
	printf("How many values are there?");
	if (scanf("%d", &n_values) != 1 || n_values <= 0)
	{
		printf("Illegal number of values.\n");
		exit(EXIT_FAILSE);
	}
	
	// 分配内存,用于存储这些变量
	array = malloc(n_values * sizeof(int));
	if (array == NULL)
	{
		print ("Cant`t get memory for that many values.\n");
		exit(EXIT_FAILUSE);
	}
	
	// 读取这些值
	for (i = 0; i < n_values; i += 1)
	{
		printf("?");
		if (scanf("%d", array + 1) != 1)
		{
			printf("Error reading value #%d\n", i);
			free(array);
			exit(EXIT_FAILURE);	
		}
	}
	
	// 对这些值排序
	qsort(array, n_values, sizeof(int), compare_integers);
	
	// 打印这些元素
	for (i = 0; i < n_values; i += 1)
	{
		printf("%d\n", array[i]);
	}
	
	// 释放内存并退出
	free(array);
	return EXIT_SUCCESS;
}



// 用动态分配内存制作一个字符串的一份拷贝,调用程序应该检查这块内存是否分配成功
#include 
#include 

char* strdup(char const* string)
{
	char* new_string;
	
	// 请求足够长的内存,用于存储字符串和他结尾的NUL字节
	new_string = malloc(strlen(string) + 1);
	
	// 如果我们得到内存,就复制字符串
	if (new_string != NULL)
		strcpy(new_string, string);
	
	return new_string;
}
// 存货记录声明

// 包含零件专用信息的结构
typedef struct 
{
	int cost;
	int supplier;
} Partinfo;

// 存储装配件专用信息的结构体
typedef struct
{
	int n_parts;
	
	struct SUBASSYPART
	{
		char partno[10];
		short quan;
	} * part;
} Subassyinfo;

// 存货记录结构,是一个变体记录
typedef struct
{
	char partno[10];
	int quan;
	enum {PART, SUBASSY} type;
	union
	{
		Partinfo* part;
		Subassyinfo* subassy;
	} info;
} Invrec;

/* nextfile.c */
/* ::[[ @(#) turboc.c 1.7 89/07/12 03:18:30 ]]:: */
#ifndef LINT
static char sccsid[]="::[[ @(#) turboc.c 1.7 89/07/12 03:18:30 ]]::";
#endif

/*
This file is used only for MS-DOS.  It is used with Turbo C 1.0.  It also
apparently works with Microsoft C 5.1 (see makefile.msc).
*/

/*
Checksum:   60385500      (check or update this with "brik")
*/

/*
nextfile() is a general wildcard expansion function that may be used
with other programs.  Usage instructions are below.  It does not
simply expand wildcards in an entire argument list.  Instead, it is
called in a loop as described below, and returns one matching
filename each time it is called.

These functions are for the SMALL MEMORY MODEL ONLY.
*/

#include "assert.h"
#include "brik.h"

#define  FMAX  2        /* Number of different filename patterns */
#define  PATHSIZE 200   /* Size of MS-DOS pathname */
#define  NULL  0

#ifdef ANSIPROTO
char *strtcpy (char *, char *);
int strlen (char *);
char *strcpy (char *, char *);
#endif


/* Structure definitions for MS-DOS software interrupt intdos() */

struct WORD_REGISTERS {
   unsigned int ax, bx, cx, dx, si, di, carry, flags;
};

/* byte registers */

struct BYTE_REGISTERS {
   unsigned char al, ah, bl, bh, cl, ch, dl, dh;
};

union REGS {
   struct WORD_REGISTERS x;
   struct BYTE_REGISTERS h;
};

int intdos (union REGS *, union REGS *);

/*
format of disk transfer address after MS-DOS calls FindFirst and
FindNext
*/
struct dta_t {
   char junk[22];
   int time;
   int date;
   long size;
   char fname[13];
   char just_in_case[4];   /* in case MS-DOS writes too much */
};

void setdta (struct dta_t *);
void fcbpath (struct dta_t *, char *, char *);

/*******************/
/*
nextfile() returns the name of the next source file matching a filespec.

INPUT
   what: A flag specifying what to do.  If "what" is 0, nextfile()
      initializes itself.  If "what" is 1, nextfile() returns the next
      matching filename.
   filespec:  The filespec, usually containing wildcard characters, that
      specifies which files are needed.  If "what" is 0, filespec must be
      the filespec for which matching filenames are needed.  If "what" is 1,
      nextfile() does not use "filespec" and "filespec" should be NULL to
      avoid an assertion error during debugging.
   fileset:  nextfile() can keep track of more than one set of filespecs.
      The fileset specifies which filespec is being matched and therefore
      which set of files is being considered.  "fileset" can be in the
      range 0:FMAX.  Initialization of one fileset does not affect the
      other filesets.

OUTPUT
   IF what == 0 THEN
      return value is NULL
   ELSE IF what == 1 THEN
      IF a matching filename is found THEN
         return value is pointer to matching filename including supplied path
      ELSE
         IF at least one file matched previously but no more match THEN
            return value is NULL
         ELSE IF supplied filespec never matched any filename THEN
            IF this is the first call with what == 1 THEN
               return value is pointer to original filespec
            ELSE
               return value is NULL
            END IF
         END IF
      END IF
   END IF

NOTE

   Initialization done when "what"=0 is not dependent on the correctness
   of the supplied filespec but simply initializes internal variables
   and makes a local copy of the supplied filespec.  If the supplied
   filespec was illegal, the only effect is that the first time that
   nextfile() is called with "what"=1, it will return the original
   filespec instead of a matching filename.  That the filespec was
   illegal will become obvious when the caller attempts to open the
   returned filename for input/output and the open attempt fails.

USAGE HINTS

nextfile() can be used in the following manner:

      char *filespec;                  -- will point to filespec
      char *this_file;                 -- will point to matching filename
      filespec = parse_command_line(); -- may contain wildcards
      FILE *stream;

      nextfile (0, filespec, 0);          -- initialize fileset 0
      while ((this_file = nextfile(1, (char *) NULL, 0)) != NULL) {
         stream = fopen (this_file, "whatever");
         if (stream == NULL)
            printf ("could not open %s\n", this_file);
         else
            perform_operations (stream);
      }
*/

char *nextfile (what, filespec, fileset)
int what;                        /* whether to initialize or match      */
register char *filespec;         /* filespec to match if initializing   */
register int fileset;            /* which set of files                  */
{
   static struct dta_t new_dta [FMAX+1];     /* our own private dta        */
   static int first_time [FMAX+1];
   static char pathholder [FMAX+1][PATHSIZE]; /* holds a pathname to return */
   static char saved_fspec [FMAX+1][PATHSIZE];/* our own copy of filespec   */
   union REGS regs;

   assert(fileset >= 0 && fileset <= FMAX);
   if (what == 0) {
      assert(filespec != NULL);
      strcpy (saved_fspec[fileset], filespec);  /* save the filespec */
      first_time[fileset] = 1;
      return ((char *) NULL);
   }

   setdta (&new_dta[fileset]);   /* set new dta -- our very own */
   assert(what == 1);
   assert(filespec == NULL);
   assert(first_time[fileset] == 0 || first_time[fileset] == 1);

   if (first_time[fileset]) {             /* first time -- initialize etc. */
      /* find first matching file */
      regs.h.ah = 0x4e;                   /* FindFirst MS-DOS call    */
      regs.x.dx = (unsigned int) saved_fspec[fileset]; /* filespec to match */
      regs.x.cx = 0;                      /* search attributes       */
      intdos (®s, ®s);
   } else {
      /* find next matching file */
      regs.h.ah = 0x4f;                   /* FindNext MS-DOS call     */
      intdos (®s, ®s);
   }

   if (regs.x.carry != 0) {            /* if error status                  */
      if (first_time[fileset]) {       /*   if file never matched then     */
         first_time[fileset] = 0;
         return (saved_fspec[fileset]);/*      return original filespec    */
      } else {                         /*   else                           */
         first_time[fileset] = 0;      /*                                  */
         return ((char *) NULL);         /*      return (NULL) for no more   */
      }
   } else {                                        /* a file matched */
      first_time[fileset] = 0;
      /* add path info  */
      fcbpath (&new_dta[fileset], saved_fspec[fileset], pathholder[fileset]);
      return (pathholder[fileset]);                /* matching path  */
   }
} /* nextfile */

/*******************/
/* This function sets the dta to a new dta */
void setdta (dta)
struct dta_t *dta;
{
   union REGS regs;
   regs.h.ah = 0x1a;                /* SetDTA Call       */
   regs.x.dx = (unsigned int) dta;  /* new DTA address   */
   intdos (®s, ®s);
}

/*******************/
/*
fcbpath() accepts a pointer to the Disk Transfer Area, a character
pointer to a pathname that may contain wildcards, and a character
pointer to a buffer.  It copies into the buffer the path prefix from
the pathname and the filename prefix from the DTA so that it forms a
complete path.
*/

void fcbpath (dta, old_path, new_path)
struct dta_t *dta;
char *old_path;
register char *new_path;
{
   register int i;
   int length, start_pos;

   strcpy(new_path, old_path);               /* copy the whole thing first */
   length = strlen(new_path);
   i = length - 1;                           /* i points to end of path */
   while (i >= 0 && new_path[i] != '/' && new_path[i] != '\\' && new_path[i] != ':')
      i--;
   /* either we found a "/", "\", or ":", or we reached the beginning of
      the name.  In any case, i points to the last character of the
      path part. */
   start_pos = i + 1;
   for (i = 0; i < 13; i++)
      new_path[start_pos+i] = dta->fname[i];
   new_path[start_pos+13] = '\0';
}
/* -- END OF nextfile() and related functions -- */

extern unsigned _stklen = 30000;

#include 
void brktst() { kbhit(); }      /* test for user interrupt */

#ifdef CTRLZ_CHECK
# define CTRLZ_BUFSIZ   1024
# include 
# include 

/*
z_bin_check is called to see if the specified file is a
binary file.  If so, it will return nonzero.  To avoid an early control Z
falsely indicating EOF, z_bin_check changes the mode of the file
to binary.
*/
}
int z_bin_check (fptr, fname)
FILE *fptr;
char *fname;
{
   char *p;
   char *limit;
   char buf[CTRLZ_BUFSIZ];
   int count;

   setmode (fileno(fptr), O_BINARY);   /* set stream to binary mode */
   fseek (fptr, 0L, SEEK_SET);         /* rewind */

   while ((count = fread (buf, 1, CTRLZ_BUFSIZ, fptr)) > 0) {
      limit = buf + count;
      for (p = buf;  p != limit;  p++) {
      extern char bintab[];      /* needed for BINCHAR */
         if (BINCHAR(*p))
            return (1);          /* indicate binary file */
      }
   }
   return (0);
}
#endif /* CTRLZ_CHECK */

你可能感兴趣的:(C++)