【嵌入式开发】C语言 指针数组 多维数组(二)

简介: 【嵌入式开发】C语言 指针数组 多维数组(二)

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字节的内存;  


目录
相关文章
|
1月前
|
存储 NoSQL 编译器
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
指针是一个变量,它存储另一个变量的内存地址。换句话说,指针“指向”存储在内存中的某个数据。
86 3
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
|
1月前
|
存储 编译器 C语言
【C语言】指针大小知多少 ?一场探寻C语言深处的冒险 !
在C语言中,指针的大小(即指针变量占用的内存大小)是由计算机的体系结构(例如32位还是64位)和编译器决定的。
56 9
|
1月前
|
安全 程序员 C语言
【C语言】指针的爱恨纠葛:常量指针vs指向常量的指针
在C语言中,“常量指针”和“指向常量的指针”是两个重要的指针概念。它们在控制指针的行为和数据的可修改性方面发挥着关键作用。理解这两个概念有助于编写更安全、有效的代码。本文将深入探讨这两个概念,包括定义、语法、实际应用、复杂示例、最佳实践以及常见问题。
45 7
|
1月前
|
传感器 算法 安全
【C语言】两个数组比较详解
比较两个数组在C语言中有多种实现方法,选择合适的方法取决于具体的应用场景和性能要求。从逐元素比较到使用`memcmp`函数,再到指针优化,每种方法都有其优点和适用范围。在嵌入式系统中,考虑性能和资源限制尤为重要。通过合理选择和优化,可以有效提高程序的运行效率和可靠性。
98 6
|
2月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
71 5
|
2月前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
2月前
|
机器学习/深度学习 算法 数据挖掘
C语言在机器学习中的应用及其重要性。C语言以其高效性、灵活性和可移植性,适合开发高性能的机器学习算法,尤其在底层算法实现、嵌入式系统和高性能计算中表现突出
本文探讨了C语言在机器学习中的应用及其重要性。C语言以其高效性、灵活性和可移植性,适合开发高性能的机器学习算法,尤其在底层算法实现、嵌入式系统和高性能计算中表现突出。文章还介绍了C语言在知名机器学习库中的作用,以及与Python等语言结合使用的案例,展望了其未来发展的挑战与机遇。
52 1
|
2月前
|
人工智能 安全 算法
基于C语言的嵌入式系统开发,涵盖嵌入式系统概述、C语言的优势、开发流程、关键技术、应用实例及面临的挑战与未来趋势。
本文深入探讨了基于C语言的嵌入式系统开发,涵盖嵌入式系统概述、C语言的优势、开发流程、关键技术、应用实例及面临的挑战与未来趋势。C语言因其高效、可移植、灵活及成熟度高等特点,在嵌入式系统开发中占据重要地位。文章还介绍了从系统需求分析到部署维护的完整开发流程,以及中断处理、内存管理等关键技术,并展望了嵌入式系统在物联网和人工智能领域的未来发展。
81 1
|
2月前
|
程序员 C语言
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门。本文深入探讨了指针的基本概念、声明方式、动态内存分配、函数参数传递、指针运算及与数组和函数的关系,强调了正确使用指针的重要性,并鼓励读者通过实践掌握这一关键技能。
44 1
|
8月前
|
C语言
在C语言中多维数组名作为函数参数的应用与示例
在C语言中多维数组名作为函数参数的应用与示例
82 0