`

C语言 指针数组 多维数组

 
阅读更多

.

作者 : 万境绝尘

转载请注明出处 :http://blog.csdn.net/shulianghan/article/details/21402047

.


1. 地址算数运算示例



指针算数运算 : int *p, array[5]; p = array; p 指向一个 int 数组元素, p + i 的地址时数组中第 i 个元素的地址, 即 p + i 指向 第 i 个元素;


存储分配示例函数 :

-- char *alloc(int n) 函数 : 传入分配的字符个数, 返回连续字符存储单元指针, 这个指针可以存储 n 个字符元素;

-- int afree(char *p) 函数 : 释放分配的内存空间;

-- 缺陷 : 分配内存的时候, 有一个偏移量, 偏移量的大小代表已经分配了多少内存, 释放内存必须按照分配内存的顺序释放, 否则偏移量就会乱;

-- 内存分配原理 : 设置一个大数组, 内存分配就分配这个数组的中的空间, alloc 和 afree 函数操作的是指针, 不是数组, 因此这个数组可以隐藏, 将数组定义为static 类型, 那么在其它文件中, 不能访问该数组, 设置一个偏移量, 当分配 n 个元素, 偏移量就加上 n, 当偏移量 等于 数组大小, 说明内存全部分配完毕;

-- 偏移量设计 : 设置一个偏移量, 偏移量始终指向大数组的下一个空闲的元素地址, 当分配内存的时候, 通过计算 数组首地址 + 数组长度 - 偏移量 >= 分配大小 , 成立的话就可以分配内存, 分配内存就是将偏移量 加上 分配大小; 释放内存的时候, 就将偏移量 指向 释放内存的指针的首地址, 因此 要保持后进先出的次序;


代码 :

/*************************************************************************
    > File Name: alloc_afree.c
    > Author: octopus
    > Mail: octopus_work.163.com 
    > Created Time: 2014年03月17日 星期一 19时34分08秒
 ************************************************************************/

#include<stdio.h>

//用于内存分配载体的大数组大小
#define ALLOCSIZE 1000
/*
 * 该数组就是用于内存分配的主体, 
 * 设置为static , 意味着只能在本文件中访问, 在其它文件中不能访问
 */
static char alloc_buf[ALLOCSIZE];
/*
 * 将alloc_buf 数组的首地址赋值给allocp字符指针
 * 对allocp 进行算数运算, 每次加减都是 char * 运算数
 * allocp的值就可以代表所分配内存的首地址
 */
static char *allocp = alloc_buf;

/*
 * 分配n个char类型数组的内存, 
 * 如果分配成功, 返回分配的内存的指针,
 * 如果分配失败, 返回0
 */
char *alloc(int n)
{
	//如果大数组剩余的空间可以分配, 那么就进行分配
	if(alloc_buf + ALLOCSIZE - allocp >= n)
	{
		//分配空间, allocp 指向下一个空间的内存首地址
		allocp += n;
		//返回分配的空间首地址
		return allocp - n;
	}else //如果数组剩余空间不足, 返回0
	{
		return 0;
	}
}

/*
 * 释放分配的内存
 * 释放内存就是将allocp 指针地址指向 要释放的内存指针首地址
 */
void afree(char *p)
{
	//释放内存的前提是 内存必须是大于数组首地址, 小于数组尾地址
	if(p >= alloc_buf && p < alloc_buf + ALLOCSIZE)
	{
		allocp = p;
		printf("allocp = %p \n", allocp);
	}
}

int main(int argc, char **argv)
{
	char *p1;
	char *p2;
	char *p3;
	char *p4;

	//打印数组首地址
	printf("alloc_buf = %p \n", alloc_buf);

	//分配300个字符内存
	p1 = alloc(300);
	printf("char *p1 = alloc(300), p1 = %p \n", p1);

	p2 = alloc(300);
	printf("char *p2 = alloc(300), p2 = %p \n", p2);

	p3 = alloc(300);
	printf("char *p3 = alloc(300), p3 = %p \n", p3);

	//上面已经分配了900了, 在分配就溢出了, 这里alloc()函数返回0
	p4 = alloc(300);
	printf("char *p4 = alloc(300), p4 = %p \n", p4);

	afree(p4);
	afree(p3);
	afree(p2);
	afree(p1);
}

执行结果 :

octopus@octopus-Vostro-270s:~/code/c/pointer$ gcc alloc_afree.c 
octopus@octopus-Vostro-270s:~/code/c/pointer$ ./a.out 
alloc_buf = 0x804a060 
char *p1 = alloc(300), p1 = 0x804a060 
char *p2 = alloc(300), p2 = 0x804a18c 
char *p3 = alloc(300), p3 = 0x804a2b8 
char *p4 = alloc(300), p4 = (nil) 
allocp = 0x804a2b8 
allocp = 0x804a18c 
allocp = 0x804a060 


函数执行示例图 :

-- alloc()函数示例图 :


-- afree()函数示例图 :




指针初始化 : static char *allocp = alloc_buf, 将char数组的首地址赋值给char类型指针;

-- 初始化内容 : 0 或者 地址;

-- 地址限定 : 对指针初始化的地址, 该地址存储的数据的类型必须是该指针类型;


内存可用判断 : alloc_buf + ALLOCSIZE - allocp >= n;

-- 意义 : alloc_buf 是数组首地址, ALLOCSIZE 是数组大小, allocp是可用内存偏移量, alloc_buf + ALLOCSIZE -allocp 结果是可用的内存量, 如果可用内存大于n, 则可以赋值;

-- 如果内存不足 : 内存不足, 将0作为地址返回, C语言中设定 0 不是有效的数据地址, 0地址的数据为NULL, 返回0表示发生了异常事件;


指针整数转换特例 : 指针 和 整数 不能相互转换;

-- 通常情况 : 指针 和 整型 之间不能相互转换, 0 除外;

-- 特例 : 常量 0 可以赋值给指针, 指针 可以和 常量 0 进行比较, 这里注意是常量;

-- 0的特殊性 : NULL 可以代替 常量0, 常量0 是一个特殊值;


指针运算 :

-- 比较运算 : 两个指针都指向同一个数组中的元素, 那么两个指针之间的比较是有意义的, 指向两个不同数组元素的指针之间比较无意义;

-- 加减运算 : 指向数组元素的指针, 进行加减运算, 地址的计算按照 运算数 * 指针指向元素的大小 进行计算;


计算字符串长度示例 :

-- 代码 :

/*************************************************************************
    > File Name: strlen_pointer.c
    > Author: octopus
    > Mail: octopus_work.163.com 
    > Created Time: 2014年03月17日 星期一 21时38分52秒
 ************************************************************************/

#include<stdio.h>

//计算字符串长度
int strlen(char *s)
{
	//指针 p 记录首地址
	char *p = s;
	//循环获取字符串最后的字符首地址
	while(*p != '\0')
		p++;
	//字符串占用的内存地址个数
	return p - s;
}

int main(int argc, char **argv)
{
	char *c = "fuck you!!";

	printf("length = %d \n", strlen(c));

	return 0;
}

-- 执行效果 :

octopus@octopus-Vostro-270s:~/code/c/pointer$ gcc strlen_pointer.c 
octopus@octopus-Vostro-270s:~/code/c/pointer$ ./a.out 
length = 10 


指针差值类型 :

-- ptrdiff_t : 该类型定义在 stddef.h 头文件中, 表示两个指针之间的带符号的差值;

-- size_t : 该类型定义在 stdio.h 头文件中, size_t 可以作为 sizeof 返回的无符号整型;


指针运算一致性 : 指针运算会自动考虑其指向的元素的长度, p 指向一个类型元素 a, 不管 a 占多少字节, p++ 的下一个元素都指向下一个 同类型的元素;


指针之间的有效运算 : 除下面几种合法运算之外, 其它运算都是非法的, 但不会报错, 会警告;

-- 赋值 : 同类型指针之间的赋值运算;

-- 算数 : 指针与整数的加减运算;

-- 0相关 : 指针与0 的赋值运算, 比较运算;



2. 字符指针与函数示例



字符串常量 : 字符串常量是一个字符数组;

-- 字符串常量界定 : 字符数组以 '\0' 结束, 程序通过检查 NULL 字符找到字符串的结尾;

-- 长度大于1 : 字符串常量占据的存储单元 比 字符的个数 多1位, 这一位是 '\0';


常量字符串访问方式 : 通过指针进行访问, 指针指向常量字符串的第一个字符, 程序可以通过这个指针操作字符串常量;


字符串定义方式 :

-- 数组 : char array[] = "fuck"; array 存放 fuck 字符串 和 '\0', array 地址是字符串首地址;

-- 指针 : char *c = "fuck"; 将字符串的首地址赋值给指针c, 没有经过字符串复制;

-- 区别 : 数组 - array 指向的地址不能改变, 单个字符可以修改; 指针 - c 指向字符串常量, 可以被修改指向其它地址, 修改字符串内容没有意义, 这样会在创建一个字符串常量, 并将首地址赋值给指针;



示例代码 : 分别用数组 和 指针 用法 拷贝字符串, 字符串比较;

/*************************************************************************
    > File Name: string.c
    > Author: octopus
    > Mail: octopus_work.163.com 
    > Created Time: Tue 18 Mar 2014 12:34:20 AM CST
 ************************************************************************/

#include<stdio.h>

/*
 * 字符串拷贝
 * 将 source[i] 赋值给 density[i], 每次循环 i++ 
 * 当density[i] == '\0'的时候停止循环
 */ 
void strcpy_array(char *density, char *source)
{
        int i = 0;
        while((density[i] = source[i]) != '\0')
                i++;
} 

/*
 * 字符串拷贝
 * *density++ 是对*density地址指向的值赋值, 然后地址进行自增操作
 * *source++ 是先取出source 指向的地址的值, 然后地址进行自增操作
 */
void strcpy_pointer(char *density, char *source)
{
        while(*density++ = *source++);
}

/*
 * s[i] == t[i] 前提下 s[i] = '\0'
 * 此时 返回 s[i] - t[i] 
 * 如果返回0 
 */
int strcmp_array(char *s, char *t)
{
        int i;
        for(i = 0; s[i] == t[i]; i++)
                if(s[i] == '\0')
                        return 0;
        return s[i] - t[i];
}

int strcmp_pointer(char *s, char *t)
{
        for(; *s == *t; s++, t++)
                if(*s == '\0')
                        return 0;
        return *s - *t;
}

int main(int argc, char **argv)
{
        char *source = "octopus";
        char density[10];

        printf("strcmp_array = %d \n", strcmp_array(density, source));
        printf("strcmp_pointer = %d \n", strcmp_pointer(density, source));

        strcpy_pointer(density, source);

        //打印字符串, 使用 字符串首地址 替代 %s;
        printf("source = %s \n", source);
        printf("density = %s \n", density);
}

运行结果 :

[root@ip28 pointer]# gcc string.c 
[root@ip28 pointer]# ./a.out 
strcmp_array = -239 
strcmp_pointer = -239 
source = octopus 
density = octopus 


* 和 自增(减) 运算 :

-- *source++ : 上面的该表达式的意义是 执行 自增运算之前, source 指针指向的字符, 读取到该字符之后, 该指针指向的地址 +1;

-- *density++ = *source++ : source指针自增前, 现将其指向的字符 赋值给 density 之前指向的地址的字符, 然后将 source 指针 +1;

-- 入栈 : *p++ = val, 这是标准的入栈操作, 将val压入栈, 然后指针自增1, 注意, 这里最后一个栈多加了一个1, 然后出栈的时候要先减1 在取值;

-- 出栈 : val = *--p, 这是标准的出栈操作, 现将指针减一, 然后取出指针指向的数据, 因为指针总是指向首地址, 如果我们想要取出某一段的值, 先要将指针指向首地址才可以;



3. 指针数组 指向指针的指针 示例



案例需求 :

-- 实现功能 : 在单个运算中处理长度不一的文本, 处理可变文本行数据;

-- 实际功能 : 从标准输入流中输入多个字符串, 每个字符串都使用指针指向字符串的首地址, 然后将指针存放到数组中, 对字符串数组进行排序, 按照字典顺序输出;


引入指针数组 :

-- 比较操作 : 对两个字符串进行移动 比较的时候, 使用 指向它们的指针进行操作, 比较的时候直接使用下标逐一对比;

-- 拷贝操作 : 字符串拷贝的时候, 直接将指针赋值给另一个指针即可, 不用在对文本行进行操作;

-- 好处 : 消除了移动文本带来的内存管理 和 开销;


函数设计 :

-- 设置函数 : 读取输入行, 文本排序, 打印文本行, 设置上面三个函数, 在 main 函数中控制函数执行;

-- 声明函数 : 在文件开始先声明一下函数, 那么在整个文件中就可以使用这个函数了, 即使函数定义在 main 函数的后面, 也可以调用;


程序要点 :

-- 输入流读取字符串 : 在for循环中获取字符, 当获取到 EOF 或者 '\n' 的 或者 获取字符超过数组大小 的时候停止获取, 返回 获取的字符串 和 个数;

-- 创建字符指针数组 : 当获取到的字符串个数为0, 停止获取字符串, 然后统计字符串个数, 根据字符串个数分配字符指针数组大小;

-- 递归排序 :

-- 打印数组 : 遍历指针数组, 将指针指向的字符串打印出来;



C程序代码 :

/*************************************************************************
    > File Name: string_sort.c
    > Author: octopus
    > Mail: octopus_work.163.com 
    > Created Time: 2014年03月18日 星期二 12时33分19秒
 ************************************************************************/

#include<stdio.h>
#include<string.h>

//定义排序的最大文本行数
#define MAXLINES 100

//文本行的指针数组, 该数组中存放的是 char 类型指针
char *lineptr[MAXLINES];

//每行输入最大文本数 10 个字符
#define MAXLEN 100


int readlines(char *lineptr[], int maxlines);
void writelines(char *lineptr[], int nlines);
void qsort(char *v[], int left, int right);


int main(int argc, char **argv)
{
	int nlines;

	if((nlines = readlines(lineptr, MAXLINES)) >= 0)
	{
		qsort(lineptr, 0, nlines - 1);
		writelines(lineptr, nlines);
		return 0;
	}
	else
	{
		printf("error : input too big data ! \n");
		return 1;
	}

	printf("fuck main \n");
	return 0;
}

/*
 * 从输入流中接收收据, 最多接收 max 个字符, 返回读取到的字符串长度
 * 注意 : 函数不能命名为 getline, 与stdio.h 中的 getline 命名冲突
 */
int get_line(char *ch, int max, int nlines)
{
	printf("input the %d char sequence : ", nlines);
	int c, i;
	/*
	 * getchar() 返回值 时 无符号的 char 类型转换成的 int 类型
	 * 将int 类型数据 赋值给 char 类型, 就是截取 int 的最后8位 即一字节赋给char变量
	 *
	 * 循环的条件 : 
	 *	输入的字符数不超过 定义的 MAXLEN 10
	 *	获取的字符不是 EOF 结束符
	 *	获取的字符不是 '\n' 回车
	 *
	 *	输入 EOF(Ctrl + D) 或者 回车 这一行的字符串就会输入完毕
	 */
	for(i = 0; i < max - 1 && (c = getchar()) != EOF && c != '\n'; i++)
		ch[i] = c;
	//给字符串加上结尾 '\0'
	ch[i] = '\0';
	return i;
}


//可分配的内存共 11000 字节, 最大文本行数 100, 每行 100字符, 最大不会超过 10000字节
#define ALLOCSIZE 11000
//alloc函数可分配的内存存储区
static char allocbuf[ALLOCSIZE];
//空间分配的辅助偏移量
static char *allocp = allocbuf;

/*
 * 分配内存
 */
char *alloc(int n)
{
	//判断剩余内存是否足够
	if(allocbuf + ALLOCSIZE - allocp >= n)
	{
		//分配内存, 将偏移量指向下一个空白内存
		allocp += n;
		//注意返回分配的内存的时候, 需要将指针指向已经分配内存的首地址
		return allocp - n;
	}else
		return 0;
}


int readlines(char *lineptr[], int maxlines)
{
	/*
	 * len 获取的字符串的字符个数, 注意 不包括 '\0', 是真实的个数
	 * nlines 初始值0, 获取的字符串个数, 即字符指针数组的大小
	 * *p alloc()方法分配内存的个数
	 * line[MAXLEN] 从输入流中获取字符串的载体
	 */
	int len, nlines;
	char *p, line[MAXLEN];
	nlines = 0;

	/*
	 * 不停的从输入流获取字符串, 放到 line 数组中, 获取的字符最多100个
	 * 如果获取的字符个数大于0, 就执行循环体内的方法
	 */
	while((len = get_line(line, MAXLEN, nlines)) > 0)
		/*
		 * 如果获取的字符串个数 超过 MAXLINES 100 个, 就返回 -1
		 * 如果没有获取到足够的内存, 就返回 -1
		 * 分配的内存要多分配1个, get_line 返回的函数小于
		 */
		if(nlines  >= MAXLINES || (p = alloc(len + 1)) == NULL)
			return -1;
		else
		{
			//拷贝获取的字符串 到 alloc 分配的内存中
			strcpy(p, line);
			//将 alloc 分配的内存 指针 放入 指针数组中
			lineptr[nlines++] = p;
		}
	return nlines;
}

/*
 * 输出指针数组 中 的指针 指向的字符串
 * 每个指针都指向一个字符串数组, 不是常量
 */
void writelines(char *lineptr[], int nlines)
{
	int i;
	printf("\n");
	//便利指针数组, 将每个指针代表的字符串打印出来
	for(i = 0; i < nlines; i++)
		printf("lineptr[%d] = %s\n", i, lineptr[i]);
}

//数组中的两个元素进行交换
void swap(char *v[], int i, int j)
{
	//每个数组元素都是 char * 类型的, 使用 temp 保存数组元素
	char *temp;

	//都是 char * 之间的数据进行赋值运算
	temp = v[i];
	v[i] = v[j];
	v[j] = temp;
}

/*
 * 参数解析 : 
 *	char *v[] : 字符指针数组
 *	int left : 排序的字符数组起始下标
 *	int right : 排序的字符数组的终止下标
 *	qsort(array, 0, 3) 将 array 中的 第0个 到 第3个 之间的字符串排序
 *
 *
 * strcmp(s1, s2)函数解析 :
 *	返回值 <0 : s1 < s2
 *	返回值 =0 : s1 = s2
 *	返回值 >0 : s1 > s2
 */
void qsort(char *v[], int left, int right)
{
	int i, last;
	//如果数组的元素个数小于2个, 返回
	if(left >= right)
		return;

	//交换最左边 和 中间元素
	swap(v, left, (left + right) / 2);
	//last 记录
	last = left;
	/*
	 * 过程解析 : last 指向第一个元素
	 * 从第二个元素开始遍历整个数组, 直到遍历结束
	 * 如果遍历的i元素 小于 left 元素
	 * 将last下标自增, 然后 与 i 位置互换
	 *
	 * 最终 除了 left 之外, 右边的last 个都比left小
	 * 将 last 与 left 互换, last 是最大的;
	 */
	for(i = left + 1; i <= right; i++)
		if(strcmp(v[i], v[left]) < 0)
			swap(v, ++last, i);
	swap(v, left, last);

	//递归进行 left 到 中间 的排序
	qsort(v, left, last - 1);
	//递归进行 中间 到 right 的排序
	qsort(v, last + 1, right);
}


运行效果 :

octopus@octopus-Vostro-270s:~/code/c/pointer$ gcc string_sort.c 
octopus@octopus-Vostro-270s:~/code/c/pointer$ ./a.out 
input the 0 char sequence : hello
input the 1 char sequence : world
input the 2 char sequence : fuck
input the 3 char sequence : you
input the 4 char sequence : my
input the 5 char sequence : load
input the 6 char sequence : down
input the 7 char sequence : up
input the 8 char sequence : ctrl
input the 9 char sequence : num
input the 10 char sequence : 12
input the 11 char sequence : 34
input the 12 char sequence : 56
input the 13 char sequence : 78
input the 14 char sequence : 35436
input the 15 char sequence : 6876
input the 16 char sequence : 
lineptr[0] = 12
lineptr[1] = 34
lineptr[2] = 35436
lineptr[3] = 56
lineptr[4] = 6876
lineptr[5] = 78
lineptr[6] = ctrl
lineptr[7] = down
lineptr[8] = fuck
lineptr[9] = hello
lineptr[10] = load
lineptr[11] = my
lineptr[12] = num
lineptr[13] = up
lineptr[14] = world
lineptr[15] = you




4. 多维数组案例



日期转程序需求 : 将某月 某日 转换成 一年中的 第多少天, 反之 将某天转换成 某年的 某月某日;

-- 月日转天 : 如 5月1日 是某一年的第几天, 注 闰年 与 非闰年不同;

-- 天转月日 : 将天数 转换成 某一年的 月份 和 日期, 注意闰年;


C程序 :

/*************************************************************************
    > File Name: multi_array.c
    > Author: octopus
    > Mail: octopus_work.163.com 
    > Created Time: 2014年03月18日 星期二 20时55分07秒
 ************************************************************************/

#include<stdio.h>

/*
 * 该二维数组中存放的是 闰年 和 非闰年 每个月的天数
 * day_table[1] 中存放的是 非闰年 每个月的天数
 * day_table[2] 中存放的时 闰年 每个月的天数
 */
static char day_table[2][13] = {
	{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
	{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

/*
 * 四年一润, 百年不润, 四百年再润
 */
int leap(int year)
{
	return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}

/*
 * 遍历每月的月份数, 将每月的天数累加 加上 日的天数
 * 得出的结果就是 某日期 在某年的天数
 */
int day_of_year(int year, int month, int day)
{
	int i;
	for(i = 1; i < month; i++)
		day += day_table[leap(year)][i];
	return day;
}

/*
 * 计算 某年的天数 是具体的 几月几日
 * 从 1 开始遍历二维数组的 某一年的月份天数
 * 如果 天数 大于 月份天数, 那么 年天数 减去 月份天数, 然后月份自增
 * 一直循环到 年天数 小于 月份天数
 * 那么此时循环 月份自增的变量就是月份数, 剩余的 年天数就是 日
 * 
 */
void date_of_year(int year, int year_day, int *pmonth, int *pday)
{
	int i, lp;
	lp = leap(year);
	for(i = 1; year_day > day_table[lp][i]; i++)
		year_day -= day_table[lp][i];\
	*pmonth = i;
	*pday = year_day;
}

int main(int argc, char **argv)
{
	/*
	 * 注意指针使用之前一定要初始化, 如果指针不初始化, 就不能使用
	 * 没有初始化的指针, 不能作为函数的参数
	 */
	int month, day;
	date_of_year(2014, 67, &month, &day);

	printf("2014-3-8 is the %d day of the year \n", day_of_year(2014, 3, 8));
	printf("the 67 day of 2014 is %d month %d day \n", month, day);

	return 0;
}

执行结果 :

octopus@octopus-Vostro-270s:~/code/c/pointer$ gcc multi_array.c 
octopus@octopus-Vostro-270s:~/code/c/pointer$ ./a.out 
2014-3-8 is the 67 day of the year 
the 67 day of 2014 is 3 month 8 day 


二维数组作参数 : 必须声明 列数, 行数可以不进行声明;

-- 函数调用二维数组本质 : 函数调用的传递的是指针, 指针指向一个数组, 这个数组存放的是指针元素, 每个指针都指向一个一维数组;

-- 必须知道一维数组大小 : 传入的只是一个指针, 如何找到数组中的第二个指针呢, 就需要知道一维数组的大小, 传入的指针 加上 一维数组地址 就是 第二个指针的大小, 如果没有一维数组大小, 那么就找不到其它的指针了;


二维数组参数正确声明 :

-- 带所有的参数 : fun(int day_table[2][13]);

-- 带列数, 不带行数 : fun(int day_table[][13]);

-- 指针参数 : fun(int (*day_table)[13]) , 代表参数是一个指针, 这个指针指向一个 由 13个元素组成的一维数组;

-- 错误情况 : fun(int *dat_table[13]) 传入的时一个 存放有 13个指针元素的 一维数组;

-- 错误情况 : fun(int day_table[2][]) 没有列数, 传入的时候只传入了首地址, 无法找到第二个指针;



5. 指针数组初始化


示例代码 :

/*************************************************************************
    > File Name: montn_name.c
    > Author: octopus
    > Mail: octopus_work.163.com 
    > Created Time: Wed 19 Mar 2014 12:58:48 AM CST
 ************************************************************************/

#include<stdio.h>

char *month_name(int n)
{
        /*
         * 初始化指针数组, 指针数组中的元素指向一个字符串
         */
        static char *name[] = {
                "Illegal month", 
                "January", "Febrary", "March",
                "April", "May", "June",
                "July", "August", "September",
                "October", "November", "December"
        };

        //返回一个指针, 这个指针指向字符串
        return (n < 1 || n > 12) ? name[0] : name[n];
}

int main(int argc, char **argv)
{
        printf("month 2 is %s \n", month_name(2));
        return 0;
}

执行结果 :

[root@ip28 pointer]# gcc montn_name.c 
[root@ip28 pointer]# ./a.out 
month 2 is Febrary 


指针数组初始化 : char *name[] 是一个指针数组, 这是一个一维数组;

-- 指针赋值 : 字符串常量 代表一个指向该常量首地址的指针, 可以将字符串常量赋值给上面的 一维指针数组;



6. 区分指针数组 与 二维数组


举例 :

int array[2][5];

int *arrayp[2];


二维数组 : 上面的 array[2][5] 是二维数组;

-- 空间分配 : 分配了 2 * 5 * sizeof(int) 大小的内存空间;

-- 计算元素地址 : 5 * row + col 是 array[row][col]的地址;


指针数组 : *array[2] 是指针数组;

-- 空间分配 : 分配了10个指针, 没有对指针进行初始化, 必须进行手动初始化, 指针指向的一维数组长度可变, 不固定;

-- 作用 : 指针数组最主要的作用是存放不同长度的字符串;


指针数组示例程序 :

/*************************************************************************
    > File Name: montn_name.c
    > Author: octopus
    > Mail: octopus_work.163.com 
    > Created Time: Wed 19 Mar 2014 12:58:48 AM CST
 ************************************************************************/

#include<stdio.h>

char *month_name(int n)
{
        /*
         * 初始化指针数组, 指针数组中的元素指向一个字符串
         */
        static char *name[] = {
                "Illegal month", 
                "January", "Febrary", "March",
                "April", "May", "June",
                "July", "August", "September",
                "October", "November", "December"
        };

        printf("sizeof(name) = %d \n", sizeof(name));
        //返回一个指针, 这个指针指向字符串
        return (n < 1 || n > 12) ? name[0] : name[n];
}

int main(int argc, char **argv)
{
        printf("month 2 is %s \n", month_name(2));
        return 0;
}

执行结果 :

[root@ip28 pointer]# gcc montn_name.c                               
[root@ip28 pointer]# ./a.out 
sizeof(name) = 104 
month 2 is Febrary 


二维数组示例程序 :

/*************************************************************************
    > File Name: montn_name.c
    > Author: octopus
    > Mail: octopus_work.163.com 
    > Created Time: Wed 19 Mar 2014 12:58:48 AM CST
 ************************************************************************/

#include<stdio.h>

char *month_name(int n)
{
        /*
         * 初始化指针数组, 指针数组中的元素指向一个字符串
         */
        static char name[][20] = {
                "Illegal month", 
                "January", "Febrary", "March",
                "April", "May", "June",
                "July", "August", "September",
                "October", "November", "December"
        };

        printf("sizeof(name) = %d \n", sizeof(name));

        //返回一个指针, 这个指针指向字符串
        return (n < 1 || n > 12) ? name[0] : name[n];
}

int main(int argc, char **argv)
{
        printf("month 2 is %s \n", month_name(2));
        return 0;
}

执行结果 :

[root@ip28 pointer]# gcc month_array.c           
[root@ip28 pointer]# ./a.out 
sizeof(name) = 260 
month 2 is Febrary 


对比 : 二维数组 占用了 260 字节内存, 指针数组占用了 104字节的内存;


.

作者:万境绝尘

转载请注明出处:http://blog.csdn.net/shulianghan/article/details/21402047

.



分享到:
评论

相关推荐

    C语言多维数组与指针

    在C语言中数组和指针之间存在一些千丝万缕的联系,搞不清楚的情况下非常容易出错,在前一段时间我写过关于数组和指针的分析,但是还是存在很多不清楚的问题,特别是当出现一些复杂的问题时,这种情况更加的复杂。...

    C语言多维数组与多级指针[参照].pdf

    C语言多维数组与多级指针[参照].pdf

    C语言中指针引用多维数组的教学实践.pdf

    C语言中指针引用多维数组的教学实践.pdf

    C语言中多维数组的内存分配和释放(malloc与free)的方法

    如果要给二维数组(m*n)分配空间,代码可以写成下面: 代码如下:char **a, i; // 先分配m个指针单元,注意是指针单元 // 所以每个单元的大小是sizeof(char *) a = (char **) malloc(m * sizeof(char * )); // 再分配n...

    C语言数组入门之数组的声明与二维数组的模拟

    这样,要“仿真”出一个多维数组就不是一件难事。 对于一个数组,我们只能够做两件事:确定该数组的大小,以及获得指向该数组下标为0的元素的指针。其他有关数组的操作,哪怕它们看上去是以数组下标进行运算的,实际...

    c语言数组与指针

    掌握数组的使用 了解多维数组的使用 掌握指针的概念和使用 了解多级指针的概念

    利用C语言的多级指针创建三维动态数组

    利用C语言的多级指针创建了三维动态数组,并操纵数组.最后释放三级指针.这个例子展示了C语言指针功能的强大、灵活与“危险”。

    C语言中数组作为函数的参数以及返回值的使用简单入门

    类似的方式,可以使用多维数组形式参数。 方式-1 形式参数为指针如下。在下一章将学习什么是指针。 void myFunction(int *param) { . . . } 方式-2 如下形式数组参数的大小: void myFunction(int param[10]) { . . ...

    多维数组管理器C语言编写

    比较实用的一个C语言编程的练习,其中包含多种存住形式,以及一些实用的编程思想!typedef struct{ char ArrayName[20]; //数组名 int dim; //数组维数 int *lower; //各维下界表指针 int *upper; //各维上界表...

    第26课 - 多维数组和多维指针.rar

    C语言数组与指针操作

    C语言全套视频教程 视频.txt

    34) C语言之指向多维数组的指针 函数 35) C语言之函数的定义和调用 36) C语言之定义带参数的函数 37) C语言之函数之形参和实参 38) C语言之函数之返回值和函数类型 39) C语言之指针做函数参数 40) C语言之数组做...

    图文详解c/c++中的多级指针与多维数组

    多维数组与多级指针是初学者经常感觉迷糊的一个地方。超过二维的数组和超过二级的指针其实并不多用。但只要掌握一定的方法,理解多级指针和“多维”数组完全可以像理解一级指针和一维数组那样简单。

    自学去c语言视频教程

    34) C语言之指向多维数组的指针 函数 35) C语言之函数的定义和调用 36) C语言之定义带参数的函数 37) C语言之函数之形参和实参 38) C语言之函数之返回值和函数类型 39) C语言之指针做函数参数 40) C语言之数组做...

    C语言初学者入门讲座 第十二讲 多维数组的指针变量

    本文给大家分享了C语言初学者入门讲座 第十二讲 多维数组的指针变量。

    C语言查询用书

    10.3.4 指向多维数组的指针和指针变量 22 10.4 字符串的指针指向字符串的针指变量 25 10.4.1 字符串的表示形式 25 10.4.2 使用字符串指针变量与字符数组的区别 28 10.5 函数指针变量 29 10.6 指针型函数 30 10.7 ...

    C语言全书word版CHAR10

    10.3.4 指向多维数组的指针和指针变量 22 10.4 字符串的指针指向字符串的针指变量 25 10.4.1 字符串的表示形式 25 10.4.2 使用字符串指针变量与字符数组的区别 28 10.5 函数指针变量 29 10.6 指针型函数 30 10.7 ...

    C语言深度解剖

    第一章 关键字 1.1 最宽恒大量的关键字auto ...4.4 指针数组与数组指针 4.5 多维数组与多级指针 4.6 数组参数与指针参数 4.7 函数指针 第五章 内存管理 5.1 什么是野指针 5.2 栈堆静态区 5.3 常见内存错误与对策

    C语言零基础最细致指针的讲解

    包含C语言的指针如下知识: 1.指针与指针变量 2.指针变量的引用 3.通过指针引用数组 4.指针的运算 5.空指针和void* 6.动态内存分配与指向它的指针变量 7.指针变量作为函数参数 ...11.指针数组和多重指针

Global site tag (gtag.js) - Google Analytics