.

作者 : 万境绝尘

转载请注明出处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, 当偏移量 等于 数组大小, 说明内存全部分配完毕;

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

代码 :

  1. /*************************************************************************
  2. > File Name: alloc_afree.c
  3. > Author: octopus
  4. > Mail: octopus_work.163.com
  5. > Created Time: 2014年03月17日 星期一 19时34分08秒
  6. ************************************************************************/
  7.  
  8. #include<stdio.h>
  9.  
  10. //用于内存分配载体的大数组大小
  11. #define ALLOCSIZE 1000
  12. /*
  13. * 该数组就是用于内存分配的主体,
  14. * 设置为static , 意味着只能在本文件中访问, 在其它文件中不能访问
  15. */
  16. static char alloc_buf[ALLOCSIZE];
  17. /*
  18. * 将alloc_buf 数组的首地址赋值给allocp字符指针
  19. * 对allocp 进行算数运算, 每次加减都是 char * 运算数
  20. * allocp的值就可以代表所分配内存的首地址
  21. */
  22. static char *allocp = alloc_buf;
  23.  
  24. /*
  25. * 分配n个char类型数组的内存,
  26. * 如果分配成功, 返回分配的内存的指针,
  27. * 如果分配失败, 返回0
  28. */
  29. char *alloc(int n)
  30. {
  31. //如果大数组剩余的空间可以分配, 那么就进行分配
  32. if(alloc_buf + ALLOCSIZE - allocp >= n)
  33. {
  34. //分配空间, allocp 指向下一个空间的内存首地址
  35. allocp += n;
  36. //返回分配的空间首地址
  37. return allocp - n;
  38. }else //如果数组剩余空间不足, 返回0
  39. {
  40. return 0;
  41. }
  42. }
  43.  
  44. /*
  45. * 释放分配的内存
  46. * 释放内存就是将allocp 指针地址指向 要释放的内存指针首地址
  47. */
  48. void afree(char *p)
  49. {
  50. //释放内存的前提是 内存必须是大于数组首地址, 小于数组尾地址
  51. if(p >= alloc_buf && p < alloc_buf + ALLOCSIZE)
  52. {
  53. allocp = p;
  54. printf("allocp = %p \n", allocp);
  55. }
  56. }
  57.  
  58. int main(int argc, char **argv)
  59. {
  60. char *p1;
  61. char *p2;
  62. char *p3;
  63. char *p4;
  64.  
  65. //打印数组首地址
  66. printf("alloc_buf = %p \n", alloc_buf);
  67.  
  68. //分配300个字符内存
  69. p1 = alloc(300);
  70. printf("char *p1 = alloc(300), p1 = %p \n", p1);
  71.  
  72. p2 = alloc(300);
  73. printf("char *p2 = alloc(300), p2 = %p \n", p2);
  74.  
  75. p3 = alloc(300);
  76. printf("char *p3 = alloc(300), p3 = %p \n", p3);
  77.  
  78. //上面已经分配了900了, 在分配就溢出了, 这里alloc()函数返回0
  79. p4 = alloc(300);
  80. printf("char *p4 = alloc(300), p4 = %p \n", p4);
  81.  
  82. afree(p4);
  83. afree(p3);
  84. afree(p2);
  85. afree(p1);
  86. }

执行结果 :

  1. octopus@octopus-Vostro-270s:~/code/c/pointer$ gcc alloc_afree.c
  2. octopus@octopus-Vostro-270s:~/code/c/pointer$ ./a.out
  3. alloc_buf = 0x804a060
  4. char *p1 = alloc(300), p1 = 0x804a060
  5. char *p2 = alloc(300), p2 = 0x804a18c
  6. char *p3 = alloc(300), p3 = 0x804a2b8
  7. char *p4 = alloc(300), p4 = (nil)
  8. allocp = 0x804a2b8
  9. allocp = 0x804a18c
  10. allocp = 0x804a060

或者 地址;

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

内存可用判断 : 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 是一个特殊值;

指针运算 :

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

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

计算字符串长度示例 :

-- 代码 :

  1. /*************************************************************************
  2. > File Name: strlen_pointer.c
  3. > Author: octopus
  4. > Mail: octopus_work.163.com
  5. > Created Time: 2014年03月17日 星期一 21时38分52秒
  6. ************************************************************************/
  7.  
  8. #include<stdio.h>
  9.  
  10. //计算字符串长度
  11. int strlen(char *s)
  12. {
  13. //指针 p 记录首地址
  14. char *p = s;
  15. //循环获取字符串最后的字符首地址
  16. while(*p != '\0')
  17. p++;
  18. //字符串占用的内存地址个数
  19. return p - s;
  20. }
  21.  
  22. int main(int argc, char **argv)
  23. {
  24. char *c = "fuck you!!";
  25.  
  26. printf("length = %d \n", strlen(c));
  27.  
  28. return 0;
  29. }

-- 执行效果

  1. octopus@octopus-Vostro-270s:~/code/c/pointer$ gcc strlen_pointer.c
  2. octopus@octopus-Vostro-270s:~/code/c/pointer$ ./a.out
  3. 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 指向字符串常量, 可以被修改指向其它地址, 修改字符串内容没有意义, 这样会在创建一个字符串常量, 并将首地址赋值给指针;

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

  1. /*************************************************************************
  2. > File Name: string.c
  3. > Author: octopus
  4. > Mail: octopus_work.163.com
  5. > Created Time: Tue 18 Mar 2014 12:34:20 AM CST
  6. ************************************************************************/
  7.  
  8. #include<stdio.h>
  9.  
  10. /*
  11. * 字符串拷贝
  12. * 将 source[i] 赋值给 density[i], 每次循环 i++
  13. * 当density[i] == '\0'的时候停止循环
  14. */
  15. void strcpy_array(char *density, char *source)
  16. {
  17. int i = 0;
  18. while((density[i] = source[i]) != '\0')
  19. i++;
  20. }
  21.  
  22. /*
  23. * 字符串拷贝
  24. * *density++ 是对*density地址指向的值赋值, 然后地址进行自增操作
  25. * *source++ 是先取出source 指向的地址的值, 然后地址进行自增操作
  26. */
  27. void strcpy_pointer(char *density, char *source)
  28. {
  29. while(*density++ = *source++);
  30. }
  31.  
  32. /*
  33. * s[i] == t[i] 前提下 s[i] = '\0'
  34. * 此时 返回 s[i] - t[i]
  35. * 如果返回0
  36. */
  37. int strcmp_array(char *s, char *t)
  38. {
  39. int i;
  40. for(i = 0; s[i] == t[i]; i++)
  41. if(s[i] == '\0')
  42. return 0;
  43. return s[i] - t[i];
  44. }
  45.  
  46. int strcmp_pointer(char *s, char *t)
  47. {
  48. for(; *s == *t; s++, t++)
  49. if(*s == '\0')
  50. return 0;
  51. return *s - *t;
  52. }
  53.  
  54. int main(int argc, char **argv)
  55. {
  56. char *source = "octopus";
  57. char density[10];
  58.  
  59. printf("strcmp_array = %d \n", strcmp_array(density, source));
  60. printf("strcmp_pointer = %d \n", strcmp_pointer(density, source));
  61.  
  62. strcpy_pointer(density, source);
  63.  
  64. //打印字符串, 使用 字符串首地址 替代 %s;
  65. printf("source = %s \n", source);
  66. printf("density = %s \n", density);
  67. }

运行结果

  1. [root@ip28 pointer]# gcc string.c
  2. [root@ip28 pointer]# ./a.out
  3. strcmp_array = -239
  4. strcmp_pointer = -239
  5. source = octopus
  6. 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程序代码 :

  1. /*************************************************************************
  2. > File Name: string_sort.c
  3. > Author: octopus
  4. > Mail: octopus_work.163.com
  5. > Created Time: 2014年03月18日 星期二 12时33分19秒
  6. ************************************************************************/
  7.  
  8. #include<stdio.h>
  9. #include<string.h>
  10.  
  11. //定义排序的最大文本行数
  12. #define MAXLINES 100
  13.  
  14. //文本行的指针数组, 该数组中存放的是 char 类型指针
  15. char *lineptr[MAXLINES];
  16.  
  17. //每行输入最大文本数 10 个字符
  18. #define MAXLEN 100
  19.  
  20. int readlines(char *lineptr[], int maxlines);
  21. void writelines(char *lineptr[], int nlines);
  22. void qsort(char *v[], int left, int right);
  23.  
  24. int main(int argc, char **argv)
  25. {
  26. int nlines;
  27.  
  28. if((nlines = readlines(lineptr, MAXLINES)) >= 0)
  29. {
  30. qsort(lineptr, 0, nlines - 1);
  31. writelines(lineptr, nlines);
  32. return 0;
  33. }
  34. else
  35. {
  36. printf("error : input too big data ! \n");
  37. return 1;
  38. }
  39.  
  40. printf("fuck main \n");
  41. return 0;
  42. }
  43.  
  44. /*
  45. * 从输入流中接收收据, 最多接收 max 个字符, 返回读取到的字符串长度
  46. * 注意 : 函数不能命名为 getline, 与stdio.h 中的 getline 命名冲突
  47. */
  48. int get_line(char *ch, int max, int nlines)
  49. {
  50. printf("input the %d char sequence : ", nlines);
  51. int c, i;
  52. /*
  53. * getchar() 返回值 时 无符号的 char 类型转换成的 int 类型
  54. * 将int 类型数据 赋值给 char 类型, 就是截取 int 的最后8位 即一字节赋给char变量
  55. *
  56. * 循环的条件 :
  57. * 输入的字符数不超过 定义的 MAXLEN 10
  58. * 获取的字符不是 EOF 结束符
  59. * 获取的字符不是 '\n' 回车
  60. *
  61. * 输入 EOF(Ctrl + D) 或者 回车 这一行的字符串就会输入完毕
  62. */
  63. for(i = 0; i < max - 1 && (c = getchar()) != EOF && c != '\n'; i++)
  64. ch[i] = c;
  65. //给字符串加上结尾 '\0'
  66. ch[i] = '\0';
  67. return i;
  68. }
  69.  
  70. //可分配的内存共 11000 字节, 最大文本行数 100, 每行 100字符, 最大不会超过 10000字节
  71. #define ALLOCSIZE 11000
  72. //alloc函数可分配的内存存储区
  73. static char allocbuf[ALLOCSIZE];
  74. //空间分配的辅助偏移量
  75. static char *allocp = allocbuf;
  76.  
  77. /*
  78. * 分配内存
  79. */
  80. char *alloc(int n)
  81. {
  82. //判断剩余内存是否足够
  83. if(allocbuf + ALLOCSIZE - allocp >= n)
  84. {
  85. //分配内存, 将偏移量指向下一个空白内存
  86. allocp += n;
  87. //注意返回分配的内存的时候, 需要将指针指向已经分配内存的首地址
  88. return allocp - n;
  89. }else
  90. return 0;
  91. }
  92.  
  93. int readlines(char *lineptr[], int maxlines)
  94. {
  95. /*
  96. * len 获取的字符串的字符个数, 注意 不包括 '\0', 是真实的个数
  97. * nlines 初始值0, 获取的字符串个数, 即字符指针数组的大小
  98. * *p alloc()方法分配内存的个数
  99. * line[MAXLEN] 从输入流中获取字符串的载体
  100. */
  101. int len, nlines;
  102. char *p, line[MAXLEN];
  103. nlines = 0;
  104.  
  105. /*
  106. * 不停的从输入流获取字符串, 放到 line 数组中, 获取的字符最多100个
  107. * 如果获取的字符个数大于0, 就执行循环体内的方法
  108. */
  109. while((len = get_line(line, MAXLEN, nlines)) > 0)
  110. /*
  111. * 如果获取的字符串个数 超过 MAXLINES 100 个, 就返回 -1
  112. * 如果没有获取到足够的内存, 就返回 -1
  113. * 分配的内存要多分配1个, get_line 返回的函数小于
  114. */
  115. if(nlines >= MAXLINES || (p = alloc(len + 1)) == NULL)
  116. return -1;
  117. else
  118. {
  119. //拷贝获取的字符串 到 alloc 分配的内存中
  120. strcpy(p, line);
  121. //将 alloc 分配的内存 指针 放入 指针数组中
  122. lineptr[nlines++] = p;
  123. }
  124. return nlines;
  125. }
  126.  
  127. /*
  128. * 输出指针数组 中 的指针 指向的字符串
  129. * 每个指针都指向一个字符串数组, 不是常量
  130. */
  131. void writelines(char *lineptr[], int nlines)
  132. {
  133. int i;
  134. printf("\n");
  135. //便利指针数组, 将每个指针代表的字符串打印出来
  136. for(i = 0; i < nlines; i++)
  137. printf("lineptr[%d] = %s\n", i, lineptr[i]);
  138. }
  139.  
  140. //数组中的两个元素进行交换
  141. void swap(char *v[], int i, int j)
  142. {
  143. //每个数组元素都是 char * 类型的, 使用 temp 保存数组元素
  144. char *temp;
  145.  
  146. //都是 char * 之间的数据进行赋值运算
  147. temp = v[i];
  148. v[i] = v[j];
  149. v[j] = temp;
  150. }
  151.  
  152. /*
  153. * 参数解析 :
  154. * char *v[] : 字符指针数组
  155. * int left : 排序的字符数组起始下标
  156. * int right : 排序的字符数组的终止下标
  157. * qsort(array, 0, 3) 将 array 中的 第0个 到 第3个 之间的字符串排序
  158. *
  159. *
  160. * strcmp(s1, s2)函数解析 :
  161. * 返回值 <0 : s1 < s2
  162. * 返回值 =0 : s1 = s2
  163. * 返回值 >0 : s1 > s2
  164. */
  165. void qsort(char *v[], int left, int right)
  166. {
  167. int i, last;
  168. //如果数组的元素个数小于2个, 返回
  169. if(left >= right)
  170. return;
  171.  
  172. //交换最左边 和 中间元素
  173. swap(v, left, (left + right) / 2);
  174. //last 记录
  175. last = left;
  176. /*
  177. * 过程解析 : last 指向第一个元素
  178. * 从第二个元素开始遍历整个数组, 直到遍历结束
  179. * 如果遍历的i元素 小于 left 元素
  180. * 将last下标自增, 然后 与 i 位置互换
  181. *
  182. * 最终 除了 left 之外, 右边的last 个都比left小
  183. * 将 last 与 left 互换, last 是最大的;
  184. */
  185. for(i = left + 1; i <= right; i++)
  186. if(strcmp(v[i], v[left]) < 0)
  187. swap(v, ++last, i);
  188. swap(v, left, last);
  189.  
  190. //递归进行 left 到 中间 的排序
  191. qsort(v, left, last - 1);
  192. //递归进行 中间 到 right 的排序
  193. qsort(v, last + 1, right);
  194. }

运行效果 :

  1. octopus@octopus-Vostro-270s:~/code/c/pointer$ gcc string_sort.c
  2. octopus@octopus-Vostro-270s:~/code/c/pointer$ ./a.out
  3. input the 0 char sequence : hello
  4. input the 1 char sequence : world
  5. input the 2 char sequence : fuck
  6. input the 3 char sequence : you
  7. input the 4 char sequence : my
  8. input the 5 char sequence : load
  9. input the 6 char sequence : down
  10. input the 7 char sequence : up
  11. input the 8 char sequence : ctrl
  12. input the 9 char sequence : num
  13. input the 10 char sequence : 12
  14. input the 11 char sequence : 34
  15. input the 12 char sequence : 56
  16. input the 13 char sequence : 78
  17. input the 14 char sequence : 35436
  18. input the 15 char sequence : 6876
  19. input the 16 char sequence :
  20. lineptr[0] = 12
  21. lineptr[1] = 34
  22. lineptr[2] = 35436
  23. lineptr[3] = 56
  24. lineptr[4] = 6876
  25. lineptr[5] = 78
  26. lineptr[6] = ctrl
  27. lineptr[7] = down
  28. lineptr[8] = fuck
  29. lineptr[9] = hello
  30. lineptr[10] = load
  31. lineptr[11] = my
  32. lineptr[12] = num
  33. lineptr[13] = up
  34. lineptr[14] = world
  35. lineptr[15] = you

4. 多维数组案例

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

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

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

C程序 :

  1. /*************************************************************************
  2. > File Name: multi_array.c
  3. > Author: octopus
  4. > Mail: octopus_work.163.com
  5. > Created Time: 2014年03月18日 星期二 20时55分07秒
  6. ************************************************************************/
  7.  
  8. #include<stdio.h>
  9.  
  10. /*
  11. * 该二维数组中存放的是 闰年 和 非闰年 每个月的天数
  12. * day_table[1] 中存放的是 非闰年 每个月的天数
  13. * day_table[2] 中存放的时 闰年 每个月的天数
  14. */
  15. static char day_table[2][13] = {
  16. {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
  17. {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
  18. };
  19.  
  20. /*
  21. * 四年一润, 百年不润, 四百年再润
  22. */
  23. int leap(int year)
  24. {
  25. return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
  26. }
  27.  
  28. /*
  29. * 遍历每月的月份数, 将每月的天数累加 加上 日的天数
  30. * 得出的结果就是 某日期 在某年的天数
  31. */
  32. int day_of_year(int year, int month, int day)
  33. {
  34. int i;
  35. for(i = 1; i < month; i++)
  36. day += day_table[leap(year)][i];
  37. return day;
  38. }
  39.  
  40. /*
  41. * 计算 某年的天数 是具体的 几月几日
  42. * 从 1 开始遍历二维数组的 某一年的月份天数
  43. * 如果 天数 大于 月份天数, 那么 年天数 减去 月份天数, 然后月份自增
  44. * 一直循环到 年天数 小于 月份天数
  45. * 那么此时循环 月份自增的变量就是月份数, 剩余的 年天数就是 日
  46. *
  47. */
  48. void date_of_year(int year, int year_day, int *pmonth, int *pday)
  49. {
  50. int i, lp;
  51. lp = leap(year);
  52. for(i = 1; year_day > day_table[lp][i]; i++)
  53. year_day -= day_table[lp][i];\
  54. *pmonth = i;
  55. *pday = year_day;
  56. }
  57.  
  58. int main(int argc, char **argv)
  59. {
  60. /*
  61. * 注意指针使用之前一定要初始化, 如果指针不初始化, 就不能使用
  62. * 没有初始化的指针, 不能作为函数的参数
  63. */
  64. int month, day;
  65. date_of_year(2014, 67, &month, &day);
  66.  
  67. printf("2014-3-8 is the %d day of the year \n", day_of_year(2014, 3, 8));
  68. printf("the 67 day of 2014 is %d month %d day \n", month, day);
  69.  
  70. return 0;
  71. }

执行结果

  1. octopus@octopus-Vostro-270s:~/code/c/pointer$ gcc multi_array.c
  2. octopus@octopus-Vostro-270s:~/code/c/pointer$ ./a.out
  3. 2014-3-8 is the 67 day of the year
  4. 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. 指针数组初始化

示例代码 :

  1. /*************************************************************************
  2. > File Name: montn_name.c
  3. > Author: octopus
  4. > Mail: octopus_work.163.com
  5. > Created Time: Wed 19 Mar 2014 12:58:48 AM CST
  6. ************************************************************************/
  7.  
  8. #include<stdio.h>
  9.  
  10. char *month_name(int n)
  11. {
  12. /*
  13. * 初始化指针数组, 指针数组中的元素指向一个字符串
  14. */
  15. static char *name[] = {
  16. "Illegal month",
  17. "January", "Febrary", "March",
  18. "April", "May", "June",
  19. "July", "August", "September",
  20. "October", "November", "December"
  21. };
  22.  
  23. //返回一个指针, 这个指针指向字符串
  24. return (n < 1 || n > 12) ? name[0] : name[n];
  25. }
  26.  
  27. int main(int argc, char **argv)
  28. {
  29. printf("month 2 is %s \n", month_name(2));
  30. return 0;
  31. }

执行结果

  1. [root@ip28 pointer]# gcc montn_name.c
  2. [root@ip28 pointer]# ./a.out
  3. 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个指针, 没有对指针进行初始化, 必须进行手动初始化, 指针指向的一维数组长度可变, 不固定;

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

指针数组示例程序 :

  1. /*************************************************************************
  2. > File Name: montn_name.c
  3. > Author: octopus
  4. > Mail: octopus_work.163.com
  5. > Created Time: Wed 19 Mar 2014 12:58:48 AM CST
  6. ************************************************************************/
  7.  
  8. #include<stdio.h>
  9.  
  10. char *month_name(int n)
  11. {
  12. /*
  13. * 初始化指针数组, 指针数组中的元素指向一个字符串
  14. */
  15. static char *name[] = {
  16. "Illegal month",
  17. "January", "Febrary", "March",
  18. "April", "May", "June",
  19. "July", "August", "September",
  20. "October", "November", "December"
  21. };
  22.  
  23. printf("sizeof(name) = %d \n", sizeof(name));
  24. //返回一个指针, 这个指针指向字符串
  25. return (n < 1 || n > 12) ? name[0] : name[n];
  26. }
  27.  
  28. int main(int argc, char **argv)
  29. {
  30. printf("month 2 is %s \n", month_name(2));
  31. return 0;
  32. }

执行结果

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

二维数组示例程序 :

  1. /*************************************************************************
  2. > File Name: montn_name.c
  3. > Author: octopus
  4. > Mail: octopus_work.163.com
  5. > Created Time: Wed 19 Mar 2014 12:58:48 AM CST
  6. ************************************************************************/
  7.  
  8. #include<stdio.h>
  9.  
  10. char *month_name(int n)
  11. {
  12. /*
  13. * 初始化指针数组, 指针数组中的元素指向一个字符串
  14. */
  15. static char name[][20] = {
  16. "Illegal month",
  17. "January", "Febrary", "March",
  18. "April", "May", "June",
  19. "July", "August", "September",
  20. "October", "November", "December"
  21. };
  22.  
  23. printf("sizeof(name) = %d \n", sizeof(name));
  24.  
  25. //返回一个指针, 这个指针指向字符串
  26. return (n < 1 || n > 12) ? name[0] : name[n];
  27. }
  28.  
  29. int main(int argc, char **argv)
  30. {
  31. printf("month 2 is %s \n", month_name(2));
  32. return 0;
  33. }

执行结果

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

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

.

作者 : 万境绝尘

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

.

【嵌入式开发】C语言 指针数组 多维数组的更多相关文章

  1. 论C语言中二级指针和二维数组之间的区别

    刚开始学习C语言的时候,觉得一个数组可以定义一个一级指针去访问,想当然的就觉得可以定义一个二级指针去访问二维数组.很显然这是错误的. 我们来看看C语言的数组在内存中的存储方式. 实际上C语言中的数组, ...

  2. C语言 指针数组 多维数组

    . 作者 : 万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/21402047 . 1. 地址算数运算示例 指针算数运算 ...

  3. C语言中指针和多维数组

    指针和多维数组 数组名是特殊的指针 数组是一个特殊的指针,多维数组也是更为复杂的数组,它们的关系是什么样的呢? 我们通过一个简单的例子来比较形象的了解指针和多维数组: int a[2][3]; 这是一 ...

  4. C语言学习笔记--多维数组和多维指针

    1. 指向指针的指针 (1)指针的本质是变量,会占用一定的内存空间 (2)可以定义指针的指针来保存指针变量的地址值 (3)指针是个变量,同样也存在传值调用与传址调用 重置动态空间的大小 #includ ...

  5. 嵌入式开发—C语言面试题

    嵌入式开发—C语言面试题 源地址:http://blog.csdn.net/xdx2ct1314/article/details/7358929   1. 用预处理指令#define 声明一个常数,用 ...

  6. 图解c/c++多级指针与“多维”数组

    声明:本文为原创博文,如有转载,请注明出处.若本文有编辑错误.概念错误或者逻辑错误,请予以指正,谢谢. 指针与数组是C/C++编程中非常重要的元素,同时也是较难以理解的.其中,多级指针与“多维”数组更 ...

  7. C:指针遍历二维数组

    C 指针遍历二维数组 http://blog.csdn.net/lcxandsfy/article/details/55000033 C++ 字符串指针与字符串数组 https://www.cnblo ...

  8. 图解C/C++多级指针与多维数组

    声明:本文转自 chenyang_yao ,欢迎阅读原文. 指针与数组是C/C++编程中非常重要的元素,同时也是较难以理解的.其中,多级指针与“多维”数组更是让很多人云里雾里,其实,只要掌握一定的方法 ...

  9. Go语言 - 数组 | 多维数组

    Array 数组是同一种数据类型元素的集合. 在Go语言中,数组从声明时就确定,使用时可以修改数组成员,但是数组大小不可变化. 1.数组 在定义阶段,长度和类型就固定了,以后不能更改 2.长度也是数组 ...

随机推荐

  1. Jmeter(二十)_Mock接口

    首先解释一下什么是mock接口. Mock通常是指,在测试一个对象时,我们构造一些假的对象来模拟与其交互.而这些Mock对象的行为是我们事先设定且符合预期.通过这些Mock对象来测试对象在正常逻辑,异 ...

  2. 虚拟机克隆,并设置新的ip

    6.1克隆新的虚拟机 选中某个虚拟机-à右键à管理à克隆 选择下一步 选择下一步 点击完成 6.2修改主机名 [root@hadoop3 ~]# vim/etc/sysconfig/network 将 ...

  3. 从Dynamics CRM2011到Dynamics CRM2016的升级之路

    CRM的产品更新特别快,特别是最近的几个版本,很多客户依旧停留在2011甚至是4.0,也经常会听到有人问2011能不能升级至最新版,2013能不能升级至最新版,本文将简单演示下从2011升级到2016 ...

  4. [ExtJS5学习笔记]第三十五节 sencha extjs 5 组件查询方法总结

    一个UI前台组件肯定会比较多,我们通常习惯性的使用ID来获取需要操作的组件,但是这种方法是extjs推荐的么?有没有extjs推荐使用的获取组件的方法呢? 目录 目录 extjs的查询组件的API 查 ...

  5. 开源框架Volley的使用《二》[NetWorkImageView&&LruCache&ImageLoader]

    转载本专栏每一篇博客请注明转载出处地址,尊重原创.此博客转载链接地址:小杨的博客    http://blog.csdn.net/qq_32059827/article/details/5278849 ...

  6. Android开发艺术探索笔记——第一章:Activity的生命周期和启动模式

    Android开发艺术探索笔记--第一章:Activity的生命周期和启动模式 怀着无比崇敬的心情翻开了这本书,路漫漫其修远兮,程序人生,为自己加油! 一.序 作为这本书的第一章,主席还是把Activ ...

  7. Compass 更智能的搜索引擎(2)--进阶

    经过了Compass 更智能的搜索引擎(1)–入门的学习,想必对于Compass的使用有了更深的认识了吧.下面谈点更加切合实际开发的东西.那就是CRUD. 面向对象的分页 dao层实现 代码释义 优点 ...

  8. JAVA面向对象-----多态

    多态的概述 1:什么是多态 一个对象的多种状态 (老师)(员工)(儿子) 教师 a =老钟; 员工 b= 老钟; 2:多态体现 1:Father类 1:非静态成员变量x 2:静态成员变量y 3:非静态 ...

  9. TCP的发送系列 — tcp_sendmsg()的实现(一)

    主要内容:Socket发送函数在TCP层的实现 内核版本:3.15.2 我的博客:http://blog.csdn.net/zhangskd 上一篇blog讲的是send().sendto().sen ...

  10. UNIX网络编程——select函数的并发限制和 poll 函数应用举例

    一.用select实现的并发服务器,能达到的并发数,受两方面限制 1.一个进程能打开的最大文件描述符限制.这可以通过调整内核参数.可以通过ulimit -n来调整或者使用setrlimit函数设置,  ...