C语言学习笔记--多维数组和多维指针
1. 指向指针的指针
(1)指针的本质是变量,会占用一定的内存空间
(2)可以定义指针的指针来保存指针变量的地址值
(3)指针是个变量,同样也存在传值调用与传址调用
重置动态空间的大小
#include <stdio.h>
#include <malloc.h> int reset(char**p,int size,int new_size)
{
int ret = ;
int i = ;
int len = ;
char* pt = NULL;
char* pp = *p; if((p != NULL)&&(new_size > ))
{
pt = (char*)malloc(new_size); len = (size < new_size)?size : new_size;//取较小者 //复制原内容
for(i=; i<len;i++){
*pt = *pp++;
} free(*p); //释放原空间
*p = pt; //*p指针指向新空间
}
else
{
ret = ;
} return ret;
} int main(int argc,char* argv[], char* env[])
{ char*p =(char*)malloc(); printf("%p\n", p);//重置前二维数组的内存地址 //重置大小后二维数组的内存地址
//因为重置后的内存地址可以是新的地址,所以这里
//需传入p指针的地址,以便在reset函数内部改变p,让
//p指向新的地址。
if (reset(&p, , ))
{
printf("%p\n", p);
} free(p);
return ;
}
2.二维数组与二级指针

(1)二维数组在内存中以一维的方式排布
(2)二维灵敏组中的第一维是一维数组
(3)二维数组中的第二维才是具体的值
(4)二维数组的数组名可看做常量指针
#include <stdio.h> //以一维数组的方式来遍历二维数组
void printfArray(int a[],int size)
{
int i = ; printf("printfArray:%d\n",sizeof(a)); //退化为指针 for(i=; i<size; i++)
{
printf("%d\n",a[i]);
}
} int main(int argc,char* argv[], char* env[])
{
int a[][] = {{, , },{, , },{, , }};
int* p = &a[][];//指向a[0][0]元素 int i;
int j; for(i = ;i < ; i++)
{
for(j = ;j < ;j++)
{
printf("%d, ",*(*(a + i) + j));//以指针方式访问元素
} printf("\n");
} printf("\n"); printfArray(p,);//以一维数组的方式访问二维数组 return ;
}
3. 数组名
(1)一维数组名代表数组首元素的地址:int a[5];a 的类型为 int*
(2)二维数组名同样代表数组首元素的地址:如 int a[3][5],a 的类型为 int(*)[5]。
|
二维数组 |
含义及类型 |
取地址符(&) |
sizeof |
|
数组名:a |
①二维数组名a指向数组首元素的地址,即第1行(a[0])的地址(注意,不是a[0][0]的地址)。因此,a被称为行指针,指向第1行元素(一维数组)的地址。这个元素的类型是int(*)[5](即一维数组)。所以a的类型为int(*)[5];a可以看作是行指针,②a + 1表示第二行的指针,a + i表示第i + 1行的指针(也是int(*)[5]类型)…… |
①&a表示整个二维数组的地址,所以&a + 1指向这个二维数组最后一个元素的后面。 |
①sizeof(a)表示整个二维数组的大小。 ②sizeof(&a)为指针大小4字节。 ③sizeof(*&a)等于sizeof(a) |
|
a[i] |
①a[i]的类型:如果把二维数组看作是由三个元素(一维数组)组成的数组,那么这三个一维数组的数组名分别为a[0]、a[1]、a[2]。因此,a[0]可以看作是指向第1行(一维数组)首元素(a[0][0])的地址,a[i]是指向第i + 1行(一维数组)首元素的地址,所以a[i]为int*型。 ②a[i] + 1表示这行数组第2个元素的地址,即a[i] + 1是指向a[i][1]元素的地址,*(a[i] + 1)是a[i][1]元素的值。同理,a[i] + j是指向a[i][j]的地址,*(a[i] + j)是a[i][j]的值。 |
&a[i]表示第i + 1行这行整个一维数组的地址。因此,&a[i] + 1是指向这行数组的下一行的指针。 |
①sizeof(a[i]):a[i]是一个一维数组。sizeof(a[i])为这个数组的大小。 ②sizeof(&a[i])为指针大小4字节。 ③sizeof(*&a[i])等于sizeof(a[i]) |
|
a[i][j] |
与a、a[i]类型的含义不同,a[i][j]不再是一个指针,而是元素的类型,即int型。 |
&a[i][j]表示这个元素的地址,即int*型 |
①sizeof(a[i][j]):a[i][j]表示元素的类型。 ②sizeof(&a[i][j])为指针大小。 ③sizeof(*&a[i][j])等于sizeof(a[i][j]) |
|
备注 |
①通常情况下,数组名可看作是首元素的地址,而表格中所说的数组名a、a[i]的类型是指当他们代表各自数组的首元素时的类型。 ②但当对数组名取地址符(&)或sizeof时,它不能看作是首元素的地址,而代表的是整个数组。请注意表格中&和sizeof两列的分析。 |
||
#include <stdio.h> int main(int argc,char* argv[], char* env[])
{ int a[][] = {};
int c; printf("Information for array:a[3][5]:\n");
printf("a = 0x%08X, a + 1 = 0x%08X, sizeof(a) = %d\n", a, a + , sizeof(a));
printf("&a = 0x%08X, &a + 1 = 0x%08X, sizeof(&a) = %d, sizeof(*&a) = %d\n",
&a, &a + , sizeof(&a),sizeof(*&a)); printf("\n"); //a[i]指向一个一维数组的首元素,a[i]+1指向该行第2个元素。sizeof(a[i])时不能看成首元素,而是这行整个一维数组
for(c=;c< ;c++)
{
printf("a[%d] = 0x%08X, a[%d] + 1 = 0x%08X, sizeof(a[%d]) = %d,\n",
c, a[c], c, a[c] + ,c, sizeof(a[c]));
} printf("\n"); //对a[i]进行&取地址符时,a[i]不能看作这一行的首元素,而是整个一维数组。即&a[i]表示第i+1的整个数组
//&a[i]+1表示下一行。
for(c=;c< ;c++)
{
printf("&a[%d] = 0x%08X, &a[%d] + 1 = 0x%08X, sizeof(&a[%d]) = %d, sizeof(*&a[%d]) = %d\n",
c, &a[c],c, &a[c] + ,c, sizeof(&a[c]), c, sizeof(*&a[c]));
} return ;
} /*
输出结果:
Information for array:a[3][5]:
a = 0x0023FE80, a + 1 = 0x0023FE94, sizeof(a) = 60
&a = 0x0023FE80, &a + 1 = 0x0023FEBC, sizeof(&a) = 4, sizeof(*&a) = 60 a[0] = 0x0023FE80, a[0] + 1 = 0x0023FE84, sizeof(a[0]) = 20,
a[1] = 0x0023FE94, a[1] + 1 = 0x0023FE98, sizeof(a[1]) = 20,
a[2] = 0x0023FEA8, a[2] + 1 = 0x0023FEAC, sizeof(a[2]) = 20,
a[3] = 0x0023FEBC, a[3] + 1 = 0x0023FEC0, sizeof(a[3]) = 20,
a[4] = 0x0023FED0, a[4] + 1 = 0x0023FED4, sizeof(a[4]) = 20, &a[0] = 0x0023FE80, &a[0] + 1 = 0x0023FE94, sizeof(&a[0]) = 4, sizeof(*&a[0]) = 20
&a[1] = 0x0023FE94, &a[1] + 1 = 0x0023FEA8, sizeof(&a[1]) = 4, sizeof(*&a[1]) = 20
&a[2] = 0x0023FEA8, &a[2] + 1 = 0x0023FEBC, sizeof(&a[2]) = 4, sizeof(*&a[2]) = 20
&a[3] = 0x0023FEBC, &a[3] + 1 = 0x0023FED0, sizeof(&a[3]) = 4, sizeof(*&a[3]) = 20
&a[4] = 0x0023FED0, &a[4] + 1 = 0x0023FEE4, sizeof(&a[4]) = 4, sizeof(*&a[4]) = 20
*/
(3)二维数元素的访问方式:int a[i][j];
①a[i][j]
② *(*(a + i) + j);//a + i 是第 i+1 行首元素(一维数组)的地址,即保存一个一维数的地址,*(a + i)取出当中保存的一维数组地址。
注意这也是一个地址,而*(a + i)+j 表示在这个一维数组地址基础上加 j 的偏移处,然后*(*(a + I)+ j)取出该元素出来。
动态申请二维数组
#include <stdio.h>
#include <malloc.h> int** malloc2d(int row,int col)
{
int** ret = NULL; if((row >) && (col >))
{
int* p = NULL; //先申请第一维数组,用于存放行指针
ret = (int**)malloc(row * sizeof(int*)); //再申请整个数组存储空间的大小,用于存放所有元素
p = (int*)malloc(row * col * sizeof(int)); //将数组空间分为二维
if ((ret != NULL) && (p != NULL))
{
int i=;
for(i=; i<row; i++)
{
ret[i] = p + i*col;
}
}
else
{
free(ret);
free(p); ret = NULL;
}
} return ret;
} void free2d(int** p)
{
if(*p != NULL) //p指向二维数组
{
//*p指向p[0],而这里保存的即是
//第1个元素的地址,也是整个数
//组元素空间地址。
free(*p); //释放元素所占空间
} free(p);//释放行指针所占空间
} int main()
{
int** a = malloc2d(, );
int i = ;
int j = ; for(i=; i<; i++)
{
for(j=; j<; j++)
{
printf("%d, ",a[i][j]);
}
printf("\n");
} free2d(a); return ;
}
无法将指针变量本身传递给一个函数,须传递指针的地址
#include <stdio.h>
#include <malloc.h>
#include <string.h> void GetMemory(char* p,int num)
{
//由于p是函数参数,当函数返回时,会被释放
p = (char*)malloc(num*sizeof(char));
} void GetMemoryEx(char** p,int num)
{
//p指向一个指针,将该指针的值指向新的开辟的内存空间。
*p = (char*)malloc(num * sizeof(char));
} int main()
{
char* str = NULL; /*
//错误的做法
GetMemory(str,10);//试图让str让指向新开辟的内存空间。因为须改变
//指针str的值,所以得传递指针的地址过去。否则
//在传参时,GetMemory只是复制str的值过去。即,
//将NULL复制给参数。 strcpy(str,"hello"); free(str);//free并没有起作用,内存泄漏
*/ //正确的做法
GetMemoryEx(&str,);//将str指针的地址传递到函数里,函数内部就
//可以改变str指针的值,让其指向新的地址。 strcpy(str,"hello"); free(str);//free并没有起作用,内存泄漏 return ;
}
参考资料:
www.dt4sw.com
http://www.cnblogs.com/5iedu/category/804081.html
C语言学习笔记--多维数组和多维指针的更多相关文章
- Go语言学习笔记八: 数组
Go语言学习笔记八: 数组 数组地球人都知道.所以只说说Go语言的特殊(奇葩)写法. 我一直在想一个人参与了两种语言的设计,但是最后两种语言的语法差异这么大.这是自己否定自己么,为什么不与之前统一一下 ...
- 吴裕雄--天生自然C++语言学习笔记:C++ 数组
C++ 支持数组数据结构,它可以存储一个固定大小的相同类型元素的顺序集合.数组是用来存储一系列数据,但它往往被认为是一系列相同类型的变量. 数组的声明并不是声明一个个单独的变量,比如 number0. ...
- C语言学习笔记之成员数组和指针
成员数组和指针是我们c语言中一个非常重要的知识点,记得以前在大学时老师一直要我们做这类的练习了,但是最的还是忘记了,今天来恶补一下. 单看这文章的标题,你可能会觉得好像没什么意思.你先别下这个 ...
- C语言学习笔记之动态分配数组空间
本文为原创文章,转载请标明出处 高级语言写多了,再拿起C语言的时候,自己已经傻了... C语言中数组大小不能为变量,即使这个变量已经被赋过值了,应该使用malloc方法进行数组空间动态分配. 如下: ...
- Go语言学习笔记(三)数组 & 切片 & map
加 Golang学习 QQ群共同学习进步成家立业工作 ^-^ 群号:96933959 数组 Arrays 数组是同一种数据类型的固定长度的序列. 数组是值类型,因此改变副本的值,不会改变本身的值: 当 ...
- 【Java学习笔记之八】java二维数组及其多维数组的内存应用拓展延伸
多维数组声明 数据类型[][] 数组名称; 数据类型[] 数组名称[]; 数据类型数组名称[][]; 以上三种语法在声明二维数组时的功能是等价的.同理,声明三维数组时需要三对中括号,中括号的位置可以在 ...
- C#学习笔记(八):多维数组
一维数组 冒泡排序 二维数组 Length:取数组元素的总个数 GetLength:取不同维度的个数 using System; using System.Collections.Generic; u ...
- C语言学习笔记(五) 数组
数组 数组的出现就是为了解决大量同类型数据的存储和使用的问题: 数组的分类:一维数组.二维数组. 一维数组:为多个变量连续分配存储控件:所有的变量的数据类型必须相同:所有变量所占的字节大小必须相等: ...
- 【Java学习笔记之九】java二维数组及其多维数组的内存应用拓展延伸
多维数组声明 数据类型[][] 数组名称; 数据类型[] 数组名称[]; 数据类型数组名称[][]; 以上三种语法在声明二维数组时的功能是等价的.同理,声明三维数组时需要三对中括号,中括号的位置可以在 ...
随机推荐
- Windows 摄像头数据
1. FFmpeg获取DirectShow设备数据(摄像头,录屏) http://blog.csdn.net/leixiaohua1020/article/details/38284961 2.
- python定制
1.简单定制 a.使用time模块的localtime方法获取时间 b.time.localtime返回struct_time的时间格式 c.表现你的类:__str__和__repr__ 注:当属 ...
- review23
文件的创建与删除 当使用File类创建一个文件对象后,例如 File file = new File("C:\\myletter", "letter.txt") ...
- Redis源码分析:serverCron - redis源码笔记
[redis源码分析]http://blog.csdn.net/column/details/redis-source.html Redis源代码重要目录 dict.c:也是很重要的两个文件,主要 ...
- 分享知识-快乐自己:HttpClient 访问 WebService 开放接口
HttpClient: 场景需求如下: 1.项目中需要与一个基于HTTP协议的第三方的接口进行对接 2.项目中需要动态的调用WebService服务(不生成本地源码) 3.项目中需要利用其它网站的相关 ...
- 《Advanced Bash-scripting Guide》学习(九):备份最后一天所有修改的文件
本文所选的例子来自于<Advanced Bash-scripting Gudie>一书,译者 杨春敏 黄毅 Example 3-4. 备份最后一天所有修改的文件 #!/bin/bash # ...
- hadoop-0.20.1+120 hive-0.3.99.1+0 试用hwi(hive web interface
摘自:http://www.chinacloud.cn/show.aspx?id=3274&cid=12 [日期:2010-07-04] 来源:淘宝数据平台团队 作者: [字体:大 中 小] ...
- Java 模拟ATM(修正)
ATM机的账户记录Account有账户的唯一性标识(11个长度的字符和数字的组合),用户的姓名,操作日期(Date),操作类型,账户密码(六位的数字,可以用0开头),当前的余额(可以为0). 模拟AT ...
- python_编码集的介绍
一.unicode的解释来自百度百科 1.ASCII 最知名的可能要数被称为ASCII的7位字符集了.它是美国标准信息交换代码(American Standard Code for Inform ...
- 3.MySQL优化---单表查询优化的一些小总结(非索引设计)
整理自互联网.摘要: 接下来这篇是查询优化.其实,大家都知道,查询部分是远远大于增删改的,所以查询优化会花更多篇幅去讲解.本篇会先讲单表查询优化(非索引设计).然后讲多表查询优化.索引优化设计以及库表 ...