METHOD 1:

Consider the case where we do not know the number of elements in each row at compile time, i.e. both the number of rows and number of columns must be determined at run time. One way of doing this would be to create an array of pointers to type int and then allocate space for each row and point these pointers at each row. Consider:

 #include <stdio.h>

 int main()
{
int nrows=;  
int ncols=;
int row;
int **rowptr;
rowptr=malloc(nrows*sizeof(int *)); //分配5行(int *)型一维数组大小的空间
if (NULL==rowptr)
{
puts("\nFailure to allocate room for row pointers.\n");
exit();
}
printf("the address of rowptr is %p\n",rowptr);
printf("\nIndex Pointer(hex) Pointer(dec) Diff.(dec)");
for (row=;row<nrows;row++)
{
rowptr[row]=malloc(ncols*sizeof(int)); //rowptr指针数组的每一个指针指向一块10个int型元素大小的内存
if (NULL==rowptr[row])
{
printf("\nFailure to allocate for row[%d]\n",row);
exit();
} printf("\n%d %p %d",row,rowptr[row],rowptr[row]);
if(row>)
printf(" %d",(rowptr[row]-rowptr[row-]));
}
puts("\n"); return ;
}

The result:

In the above code rowptr is a pointer to pointer to type int. In this case it points to the first element of an array of pointers to type int. Consider the number of calls to malloc():

    To get the array of pointers             1     call
To get space for the rows 5 calls
-----
Total 6 calls

If you choose to use this approach note that while you can use the array notation(符号) to access individual elements of the array, e.g. rowptr[row][col] = 17;, it does not mean that the data in the "two dimensional array" is contiguous in memory.

If you want to have a contiguous block of memory dedicated to the storage of the elements in the array you can do it as follows:

METHOD 2:

In this method we allocate a block of memory to hold the whole array first. We then create an array of pointers to point to each row. Thus even though the array of pointers is being used, the actual array in memory is contiguous. The code looks like this:

 #include <stdio.h>

 int main()
{
int **rptr; //用来指向指针数组
int *aptr; //用来指向一个二维数组
int *testptr; //测试指针,证明二维数组是在一个连续的内存区域
int k;
int nrows=; //5行
int ncols=; //8列
int row,col; printf("we now allocate the memory for the array\n");
aptr=malloc(nrows*ncols*sizeof(int)); //分配5行8列整型二维数组大小的空间
printf("\nthe address of the array is %p\n",aptr); if (NULL==aptr) //反过来写是为了防止出错不易检查
{
puts("\nFailure to allocate room for the array");
exit();
} printf("\nwe now allocate room for the pointers to the rows\n");
rptr=malloc(nrows*sizeof(int *)); //分配5行(int *)型一维数组大小的空间
printf("\nthe address of the pointers to the rows is %p\n",rptr); if (NULL==rptr)
{
printf("\nFailure to allocate room for pointers");
exit();
} printf("\nnow we 'point' the pointers:\n");
for (k=;k<nrows;k++)
{
rptr[k]=aptr+(k*ncols); //为指针数组的每一个元素赋一个地址(存储的地址为二维数组每行的首地址)
printf("the pointer address of the rptr[%d] is %p\n",k,rptr[k]);
}
printf("\nNow we illustrate how the row pointers are incremented\n");
printf("Index Pointer(hex) Diff.(dec)"); for (row=;row<nrows;row++)
{
printf("\n%d %p",row,rptr[row]); //以十六进制打印出指针数组中存储的地址
if(row>)
printf(" %d",(rptr[row]-rptr[row-])); //①
} printf("\n\nAnd now we print out the array\n");
for (row=;row<nrows;row++)
{
for(col=;col<ncols;col++)
{
*(*(rptr+row)+col)=row+col; //移动指针数组中的指针,使其指向分配的内存块中的每一个地址,并赋值
printf("%d ",rptr[row][col]);
}
printf("\n");
} puts("\n"); printf("And now we demonstrate that they are contiguous in memory\n");
testptr=aptr; //指向二维数组首地址
for (row=;row<nrows;row++)
{
for (col=;col<ncols;col++)
{
//将以上指针在一块连续的内存中每次移动一个地址,打印其值,结果如与以上结果吻合,说明二维数组所在的内存区域是一块连续内存
printf("%d ",*(testptr++));
}
putchar('\n');
} return ;
}

The result:

Consider again, the number of calls to malloc()

    To get room for the array itself      1      call
To get room for the array of ptrs 1 call
----
Total 2 calls

Now, each call to malloc() creates additional space overhead since malloc() is generally implemented(执行) by the operating system forming a linked list which contains data concerning the size of the block. But, more importantly, with large arrays (several hundred rows) keeping track of(跟踪) what needs to be freed when the time comes can be more cumbersome(麻烦的). This, combined with the contiguousness (邻接)of the data block that permits initialization to all zeroes using memset() would seem to make the second alternative the preferred one.

注:Diff.(dec)输出结果均为8,而不是十进制数32,为什么?

想想看,8刚好是每行的元素个数,也就是说指针(地址)相减不是地址值的差8*4=32位,而是之间相隔的元素的个数。

再看一个示例:

 #include <stdio.h>
#define N 8
int main()
{
int str[N]={,,,,,,,};
int *p;
p=str;
printf("&p[0]=%p\n&p[4]=%p\n",p,&p[]);
printf("p[4]-p[0]=%d\n",(p+)-&p[]); return ;
}

结果:

As a final example on multidimensional(多维的) arrays we will illustrate the dynamic allocation of a three dimensional array. This example will illustrate one more thing to watch when doing this kind of allocation. For reasons cited above we will use the approach outlined(概括) in alternative two. Consider the following code:

 #include <stdio.h>
#include <stddef.h> int X_DIM=;
int Y_DIM=;
int Z_DIM=; int main()
{
char *space;
char ***Arr3D;
int y,z;
ptrdiff_t diff;
/*first we set aside space for the array itself*/ space=malloc(X_DIM*Y_DIM*Z_DIM*sizeof(char)); printf("the address of space is %p\n",space); /*next we allocate space of an array of pointers,each
to eventually point to first element of a
2 dimensional array of pointers to pointers*/ Arr3D=malloc(Z_DIM*sizeof(char **));
printf("the address of Arr3D is %p\n",Arr3D); /*and for each of these we assign a pointer to a newly
allocated array of pointers to a row*/ for (z=;z<Z_DIM;z++)
{
Arr3D[z]=malloc(Y_DIM*sizeof(char *)); /*and for each space in this array we put a pointer to
the first element of each row in the array space
originally allocated */ for (y=;y<Y_DIM;y++)
{
Arr3D[z][y]=space+(z*(X_DIM*Y_DIM)+y*X_DIM);
}
}
/*And, now we check each address in our 3D array to see if
the indexing of the Arr3D pointer leads through in a
continuous manner*/ for (z=;z<Z_DIM;z++)
{
printf("Location of array %d is %p\n",z,*Arr3D[z]);
for (y=;y<Y_DIM;y++)
{
printf("Array %d and Row %d starts at %p",z,y,Arr3D[z][y]);
diff=Arr3D[z][y]-space;
printf(" diff=[%d] ",diff);
printf(" z=%d y=%d\n",z,y);
}
}
return ;
}

The result:

There are a couple of points that should be made however. Let's start with the line which reads:

    Arr3D[z][y] = space + (z*(X_DIM * Y_DIM) + y*X_DIM);

Note that here space is a character pointer, which is the same type as Arr3D[z][y]. It is important that when adding an integer, such as that obtained by evaluation of the expression (z*(X_DIM * Y_DIM) + y*X_DIM), to a pointer, the result is a new pointer value. And when assigning pointer values to pointer variables the data types of the value and variable must match.

Pointers and Dynamic Allocation of Memory的更多相关文章

  1. c++: Does the new operator for dynamic allocation check for memory safety?

    Quesion: My question arises from one of my c++ exercises (from Programming Abstraction in C++, 2012 ...

  2. Safe and efficient allocation of memory

    Aspects of the present invention are directed at centrally managing the allocation of memory to exec ...

  3. Method for training dynamic random access memory (DRAM) controller timing delays

    Timing delays in a double data rate (DDR) dynamic random access memory (DRAM) controller (114, 116) ...

  4. PatentTips - Method to manage memory in a platform with virtual machines

    BACKGROUND INFORMATION Various mechanisms exist for managing memory in a virtual machine environment ...

  5. Google C++ Style Guide

    Background C++ is one of the main development languages used by many of Google's open-source project ...

  6. Google C++ 代码规范

    Google C++ Style Guide   Table of Contents Header Files Self-contained Headers The #define Guard For ...

  7. Poly

    folly/Poly.h Poly is a class template that makes it relatively easy to define a type-erasing polymor ...

  8. Linux I/O scheduler for solid-state drives

    An I/O scheduler and a method for scheduling I/O requests to a solid-state drive (SSD) is disclosed. ...

  9. Memory Allocation with COBOL

    Generally, the use of a table/array (Static Memory) is most common in COBOL modules in an applicatio ...

随机推荐

  1. error-2016-2-15

    错误:该请求包含双重转义序列,而 Web 服务器上配置的请求筛选拒绝双重转义序列原因:一些URL中可能会包含+号等符号,然后IIS7以上的版本会默认拒绝请求此URL,需要进行如下的修改. 解决PHP中 ...

  2. [Docker] docker 基础学习笔记1(共6篇)

    巩固一下yum: yum本身是centos自带的软件,可以删掉然后再重新安装. yum本身可以配置yum源,网络的,本地的都可以.之后安装docker需要配置一个扩展源.   从163的网址里边下载好 ...

  3. Regex

    1. regex with variable example: find the number and put a parenthese around the number. output: a(52 ...

  4. logback 配置详解(一)

    一:根节点<configuration>包含的属性: scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true. scanPeriod: 设置监测配置文 ...

  5. 关于 cellForRor中给cell setSelected的时机问题?

    我在  cell  里边 - (void)setSelected:(BOOL)selected animated:(BOOL)animated { [super setSelected:selecte ...

  6. 查询AD账号的SID

    在非域控的计算机上可以查询所用AD用户的SID,不过现成的工具不能直接实现此目的,我们需要在这些计算机上安装RSAT(远程服务器管理工具),然后使用dsquery和dsget命令,来快速查询AD用户的 ...

  7. Light OJ 1029- Civil and Evil Engineer (图论-最小生成树)

    题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1029 题目大意:一个发电站,给n座房子供电, 任意房子之间有电线直接或者间接相 ...

  8. hashMap的数据结构

    HashMap底层实现还是数组,只是数组的每一项都是一条链.

  9. 解决libcurl7.50.3在windows XP SP3 VC++ 6.0下编译报错 unresolved external symbol __imp__IdnToAscii@20 unresolved external symbol __imp__IdnToUnicode@20

    错误重现: --------------------Configuration: curl - Win32 LIB Debug DLL Windows SSPI DLL WinIDN--------- ...

  10. 64位windows 7下成功配置TortoiseGit使用Github服务器

    最近感觉自己电脑上的代码太乱了,东一块.西一块……于是决定使用正规的源代码管理软件来管理自己以后写的代码.以前做小项目的时候用过TortoiseSVN,感觉不错,但是速度上有点慢,于是决定尝试一下新东 ...