【嵌入式开发】C语言 命令行参数 函数指针 gdb调试(一)

简介: 【嵌入式开发】C语言 命令行参数 函数指针 gdb调试(一)

1. C语言命令行参数详解



命令行参数 : 有两个参数 int argc 和 char **argv;


-- argc : 标示输入的参数个数, 注意命令本身也是参数;


-- argv : 指向 字符串数组的指针, 每个字符串是一个参数;


-- 约定 : argv[0] 是 程序名称, argc 的最小值是1, 如果argc 是1, 那么说明 命令后面没有参数;




(1) 模仿 echo 程序 示例



echo程序示例 :



octopus@octopus-Vostro-270s:~/code/c/pointer$ echo csdn
csdn
octopus@octopus-Vostro-270s:~/code/c/pointer$ echo Hello World
Hello World

-- 分析命令行 : echo Hello World 将 Hello World 输出到命令行中, 该命令 argc 值是3, argv[0] 是 echo, argv[1] 是 Hello, argv[2] 是 World, 注意 argv[3] 是 空指针 0;



使用数组下标方式访问参数模仿echo示例程序 :



/*************************************************************************
    > File Name: echo.c
    > Author: octopus
    > Mail: octopus_work.163.com 
    > Created Time: 2014年03月19日 星期三 19时56分36秒
 ************************************************************************/
#include<stdio.h>
int main(int argc, char **argv)
{
  int i;
  for(i = 1; i < argc; i ++)
  {
  //将参数输出, 每次注意输出一个空格, 如果是最后一个那就不用输出空格了
  printf("%s%s", argv[i], (i < argc - 1) ? " " : "");
  }
  printf("\n");
  return 0;
}



执行效果 :



octopus@octopus-Vostro-270s:~/code/c/pointer$ ./echo Hello World
Hello World
使用指针访问参数模仿echo程序 : 
/*************************************************************************
    > File Name: echo_pointer.c
    > Author: octopus
    > Mail: octopus_work.163.com 
    > Created Time: 2014年03月19日 星期三 20时08分07秒
 ************************************************************************/
#include<stdio.h>
/*
 * echo Hello World
 * 循环条件 : --argc, 如果参数只有一个 echo 那么什么都不用打印
 * 打印参数个数 : 如果参数有 3 个, 那就循环 2 次, 打印两个参数
 * 打印参数 : 从 第 2 个参数开始打印
 * 打印空格 : 如果argc > 1, 说明下一轮还要继续打印, 此时打印空格
 */
int main(int argc, char **argv)
{
  while(--argc > 0)
  printf("%s%s", *++argv, (argc > 1) ? " " : "");
  printf("\n");
  return 0;
}


执行结果 :


octopus@octopus-Vostro-270s:~/code/c/pointer$ gcc echo_pointer.c -o echo
octopus@octopus-Vostro-270s:~/code/c/pointer$ ./echo Hello World
Hello World





(2) 模仿 简单grep 程序





程序介绍 : 模仿 grep 过滤, 过滤数据来自标准输入流, grep 命令匹配第一个参数, 凡是输入的字符串 包含 第一个参数字符串, 就输出这个字符串, 相当于将字符串输出了2遍;




代码 :



/*************************************************************************
    > File Name: grep.c
    > Author: octopus
    > Mail: octopus_work.163.com 
    > Created Time: 2014年03月19日 星期三 20时45分47秒
 ************************************************************************/
#include<stdio.h>
#include<string.h>
#define MAXLEN 50
//先声明函数, 才能在main函数中使用, 否则函数要在main函数之前定义才可以使用
int get_line(char *line, int max);
int main(int argc, char **argv)
{
  char line[MAXLEN];
  int found = 0;
  if(argc == 1)
  printf("wrong parameters ! \n");
  else
  /*
   * 当获取的字符个数大于1的时候
   * 比较字符串 与 参数1
   * 如果返回的不为NULL, 那么说明查找到了字串
   * 将字串打印出来
   */
  while(get_line(line, MAXLEN) > 0)
  {
    if(strstr(line, argv[1]) != NULL)
    {
    printf("%s \n", line);
    found ++;
    }
  }
  return 0;
}
/*
 * 从标准输入流中获取字符串, 将字符串存储到 char *line 指针指向的数组中
 * 注意字符串最大为50个, 字符最多有49个, 剩下的最后一位存放 '\0'
 * 从标准输入流中读取字符, 放到数组中
 * 停止读取字符条件 : 个数到达 48个, 读取到了 回车 '\n' 或者 EOF (ctrl + D)
 */
int get_line(char *line, int max)
{
  int i, c;
  for(i = 0; (c = getchar()) != '\n' && c != EOF && i < max - 1; i++)
  line[i] = c;
  line[i] = '\0';
  return i;
}


执行结果 :  参数是 abc,  如果输入的字符串包含 abc, 那么就将字符串再输出一遍;


/*************************************************************************
    > File Name: grep.c
    > Author: octopus
    > Mail: octopus_work.163.com 
    > Created Time: 2014年03月19日 星期三 20时45分47秒
 ************************************************************************/
#include<stdio.h>
#include<string.h>
#define MAXLEN 50
//先声明函数, 才能在main函数中使用, 否则函数要在main函数之前定义才可以使用
int get_line(char *line, int max);
int main(int argc, char **argv)
{
  char line[MAXLEN];
  int found = 0;
  if(argc == 1)
  printf("wrong parameters ! \n");
  else
  /*
   * 当获取的字符个数大于1的时候
   * 比较字符串 与 参数1
   * 如果返回的不为NULL, 那么说明查找到了字串
   * 将字串打印出来
   */
  while(get_line(line, MAXLEN) > 0)
  {
    if(strstr(line, argv[1]) != NULL)
    {
    printf("%s \n", line);
    found ++;
    }
  }
  return 0;
}
/*
 * 从标准输入流中获取字符串, 将字符串存储到 char *line 指针指向的数组中
 * 注意字符串最大为50个, 字符最多有49个, 剩下的最后一位存放 '\0'
 * 从标准输入流中读取字符, 放到数组中
 * 停止读取字符条件 : 个数到达 48个, 读取到了 回车 '\n' 或者 EOF (ctrl + D)
 */
int get_line(char *line, int max)
{
  int i, c;
  for(i = 0; (c = getchar()) != '\n' && c != EOF && i < max - 1; i++)
  line[i] = c;
  line[i] = '\0';
  return i;
}




要点解析 :


-- int get_line(char *line, int max)函数 : 从输入流中获取输入, 当获取到'\n'或者EOF的时候, 就会返回该字符串指针, 注意 函数如果命名为 getline()就会报错, 与库函数同名了;


--  char *strstr(const char *haystack, const char *needle)函数 : 查询 haystack字符串中 是否包含 needle 字符串, 如果包含, 就将查询到的子字符串的指针返回;






(3) 模仿带可选参数的grep程序





需求 : 给程序加上可选参数;


-- UNIX程序约定 : 命令中 负号开头的参数是可选的参数, 例如 ls -la, ls 是将目录中的文件列出, 后面的 -la 可有可无;


-- 模拟grep程序可选参数 : -x 代表打印不匹配的文本行, -n 打印行号, 可以使用 grep -x -n 格式, 也可以使用 grep -nx 格式;




要点解析 :


-- option_analysis参数 : 因为在后面需要用到 输入的过滤参数, 即argv 的非 可选参数, 在遍历可选参数的时候, 会对argv进行一系列的自增操作, 如果我们传入的是argv二级指针, 那么在函数中进行的自增操作不会改变argv值, 这里我们需要改变argv的值, 因此需要传入 argv二级指针的地址, 三级指针;


-- 区分 (*++argv)[0] 和 *++argv[0] : []的优先级最高, 下面的框图分析两种情况 , 先进行 (*++argv)[0], 然后进行 *++argv[0]运算;




(*++argv)[0] 与 *++argv[0]图解 :


-- argv参数 :


image.png


-- 执行(*++argv)[0]表达式 :

image.png



-- 执行*++argv[0]表达式 :


image.png






代码 :



/*************************************************************************
    > File Name: grep_option.c
    > Author: octopus
    > Mail: octopus_work.163.com 
    > Created Time: 2014年03月21日 星期五 09时30分07秒
 ************************************************************************/
#include<stdio.h>
#include<string.h>
#define MAXLEN 15
char line[MAXLEN];
int c, lineno = 0, except = 0, number = 0, found = 0;
int get_line(char *line, int max);
void option_analysis(int argc, char ***argv);
void out_put(char **argv);
int main(int argc, char **argv)
{
  option_analysis(argc, &argv);
  out_put(argv);
  return 0;
}
/*
 * 从标准输入流中获取字符串, 最长能获取max个
 * 个数计算 : 
 *  字符串最长是 max 个
 *  注意里面包含了 '\0' 
 *  实际字符个数只能是 max - 1 个
 *  实际的最大下标是 max - 1
 * 字符串终止 : 
 *   输入 '\n' (回车)
 *   输入 EOF (CTRL + D)
 *   字符个数达到 max - 1 个
 * 注意 : 最后一个元素赋值为 '\0'
 */
int get_line(char *line, int max)
{
  int i, c;
  for (i = 0; (c = getchar()) != '\n' && c != EOF && i < max - 1; i++)
  {
  line[i] = c;
  }
  line[i] = '\0';
  return i;
}
/*
 * 分析可选参数情况, 根据接收到的可选参数情况, 设置标识位
 *
 * 后来对方法参数进行了小修改, 这里需要改变argv指针指向, 
 * 因此需要将该指针的地址传给函数
 *
 * 区分 (*++argv)[0] 和 *++argv[0]
 *   (*++argv)[0] : 
 *     执行顺序 : (*(++argv))[0], * 和 ++ 同时存在 执行顺序自右向左
 *     执行效果 : 
 *       ++argv 将指针指向了 下标为1 的字符串首地址 
 *       *++argv 指的是第一个字符串
 *       (*++argv)[0] 获取的是第一个字符串的第0个字符元素, 这里用来判断是不是'-'
 *   *++argv[0] : 此时argv指向第二个字符串首地址
 *     执行顺序 : *(++(argv[0])) 
 *     执行效果 : 
 *       取出第0个字符串的第1个字符, 该串的第0个字符是'-'
 *       argv[0]得到第0个字符的指针
 *       ++argv[0] 是该字符串的第二个元素的地址
 *       *++argv[0] 是该字符串第二个元素
 */
void option_analysis(int argc, char ***argvp)
{
  /*
  * 根据--argc > 0 判断输入的参数, 如果 --argc 大于0, 那么说明后面还有参数 
  * 循环所有的参数, 将所有的 -可选参数遍历出来
  *
  * 每次循环 argv 指针就自增, 指向下一个参数字符串
  * 如果字符串的第0个字符是 '-',  那么该参数字符串是可选参数
  */
  while (--argc > 0 && (*++(*argvp))[0] == '-')
  {
  /*
   * 先获取这个可选字符串指针, 然后在一次遍历这个指针
   * 根据遍历的结果设置对应的标识位
   */
  while (c = *++(*argvp)[0])
  {
    switch(c)
    {
    case 'x':
      except = 1;
      break;
    case 'n':
      number = 1;
      break;
    default:
      printf("option illegal \n");
      argc = 0;
      found = -1;
      break;
    }
  }
  }
}
/*
 * 在上面的option_analysis函数中传入的argv指针的地址, 因此上面对argv的自增操作改变了指针
 * 这里的*argv 就可以取出 argv 第0个元素字符串的指针
 *
 * 如果输入的字符串能匹配参数
 *   没有输入x的情况
 *     输入了n 输出带行号, 不匹配的字符串
 *     没有输入n 输出不带行号, 不匹配的字符串
 *   如果输入了x参数
 *     输入了n 输出带行号的, 匹配的字符串
 *     没有输入n , 输出不带行号的, 匹配的字符串
 */
void out_put(char **argv)
{
  while (get_line(line, MAXLEN) > 0)
  {
  lineno++;
  if ((strstr (line, *argv) != NULL) != except)
  {
    if(number)
    printf("%d : ", lineno);
    printf("%s \n", line);
  }
  }
}



执行结果 :


/*************************************************************************
    > File Name: grep_option.c
    > Author: octopus
    > Mail: octopus_work.163.com 
    > Created Time: 2014年03月21日 星期五 09时30分07秒
 ************************************************************************/
#include<stdio.h>
#include<string.h>
#define MAXLEN 15
char line[MAXLEN];
int c, lineno = 0, except = 0, number = 0, found = 0;
int get_line(char *line, int max);
void option_analysis(int argc, char ***argv);
void out_put(char **argv);
int main(int argc, char **argv)
{
  option_analysis(argc, &argv);
  out_put(argv);
  return 0;
}
/*
 * 从标准输入流中获取字符串, 最长能获取max个
 * 个数计算 : 
 *  字符串最长是 max 个
 *  注意里面包含了 '\0' 
 *  实际字符个数只能是 max - 1 个
 *  实际的最大下标是 max - 1
 * 字符串终止 : 
 *   输入 '\n' (回车)
 *   输入 EOF (CTRL + D)
 *   字符个数达到 max - 1 个
 * 注意 : 最后一个元素赋值为 '\0'
 */
int get_line(char *line, int max)
{
  int i, c;
  for (i = 0; (c = getchar()) != '\n' && c != EOF && i < max - 1; i++)
  {
  line[i] = c;
  }
  line[i] = '\0';
  return i;
}
/*
 * 分析可选参数情况, 根据接收到的可选参数情况, 设置标识位
 *
 * 后来对方法参数进行了小修改, 这里需要改变argv指针指向, 
 * 因此需要将该指针的地址传给函数
 *
 * 区分 (*++argv)[0] 和 *++argv[0]
 *   (*++argv)[0] : 
 *     执行顺序 : (*(++argv))[0], * 和 ++ 同时存在 执行顺序自右向左
 *     执行效果 : 
 *       ++argv 将指针指向了 下标为1 的字符串首地址 
 *       *++argv 指的是第一个字符串
 *       (*++argv)[0] 获取的是第一个字符串的第0个字符元素, 这里用来判断是不是'-'
 *   *++argv[0] : 此时argv指向第二个字符串首地址
 *     执行顺序 : *(++(argv[0])) 
 *     执行效果 : 
 *       取出第0个字符串的第1个字符, 该串的第0个字符是'-'
 *       argv[0]得到第0个字符的指针
 *       ++argv[0] 是该字符串的第二个元素的地址
 *       *++argv[0] 是该字符串第二个元素
 */
void option_analysis(int argc, char ***argvp)
{
  /*
  * 根据--argc > 0 判断输入的参数, 如果 --argc 大于0, 那么说明后面还有参数 
  * 循环所有的参数, 将所有的 -可选参数遍历出来
  *
  * 每次循环 argv 指针就自增, 指向下一个参数字符串
  * 如果字符串的第0个字符是 '-',  那么该参数字符串是可选参数
  */
  while (--argc > 0 && (*++(*argvp))[0] == '-')
  {
  /*
   * 先获取这个可选字符串指针, 然后在一次遍历这个指针
   * 根据遍历的结果设置对应的标识位
   */
  while (c = *++(*argvp)[0])
  {
    switch(c)
    {
    case 'x':
      except = 1;
      break;
    case 'n':
      number = 1;
      break;
    default:
      printf("option illegal \n");
      argc = 0;
      found = -1;
      break;
    }
  }
  }
}
/*
 * 在上面的option_analysis函数中传入的argv指针的地址, 因此上面对argv的自增操作改变了指针
 * 这里的*argv 就可以取出 argv 第0个元素字符串的指针
 *
 * 如果输入的字符串能匹配参数
 *   没有输入x的情况
 *     输入了n 输出带行号, 不匹配的字符串
 *     没有输入n 输出不带行号, 不匹配的字符串
 *   如果输入了x参数
 *     输入了n 输出带行号的, 匹配的字符串
 *     没有输入n , 输出不带行号的, 匹配的字符串
 */
void out_put(char **argv)
{
  while (get_line(line, MAXLEN) > 0)
  {
  lineno++;
  if ((strstr (line, *argv) != NULL) != except)
  {
    if(number)
    printf("%d : ", lineno);
    printf("%s \n", line);
  }
  }
}
相关实践学习
阿里云图数据库GDB入门与应用
图数据库(Graph Database,简称GDB)是一种支持Property Graph图模型、用于处理高度连接数据查询与存储的实时、可靠的在线数据库服务。它支持Apache TinkerPop Gremlin查询语言,可以帮您快速构建基于高度连接的数据集的应用程序。GDB非常适合社交网络、欺诈检测、推荐引擎、实时图谱、网络/IT运营这类高度互连数据集的场景。 GDB由阿里云自主研发,具备如下优势: 标准图查询语言:支持属性图,高度兼容Gremlin图查询语言。 高度优化的自研引擎:高度优化的自研图计算层和存储层,云盘多副本保障数据超高可靠,支持ACID事务。 服务高可用:支持高可用实例,节点故障迅速转移,保障业务连续性。 易运维:提供备份恢复、自动升级、监控告警、故障切换等丰富的运维功能,大幅降低运维成本。 产品主页:https://www.aliyun.com/product/gdb
目录
相关文章
|
1月前
|
NoSQL 搜索推荐 openCL
【C/C++ 调试 GDB指南 】gdb调试基本操作
【C/C++ 调试 GDB指南 】gdb调试基本操作
53 2
|
1月前
|
存储 编解码 编译器
嵌入式C语言(四)
嵌入式C语言(四)
27 0
|
1月前
|
存储 编译器 Linux
嵌入式C语言(三)
嵌入式C语言(三)
26 0
|
1月前
|
C语言
嵌入式C语言中的工具代码助你一臂之力
嵌入式C语言中的工具代码助你一臂之力
21 0
|
13天前
|
存储 编译器 C语言
嵌入式C语言(六)
嵌入式C语言(六)
19 0
|
22天前
|
C语言
C语言使用宏定义实现等级调试输出PRINT_LEVEL
C语言使用宏定义实现等级调试输出PRINT_LEVEL
|
28天前
|
存储 程序员 编译器
C语言第十三弹---VS使用调试技巧
C语言第十三弹---VS使用调试技巧
|
1月前
|
NoSQL 算法 Shell
【C/C++ 调试 GDB指南 】详解 gdb 断点的设置方式
【C/C++ 调试 GDB指南 】详解 gdb 断点的设置方式
19 2
|
1月前
|
存储 程序员 编译器
c语言从入门到实战——VS2022实用调试技巧
Visual Studio是集成开发环境,其内置了多种调试工具和技巧帮助开发人员在开发过程中解决问题。以下是一些VS实用调试技巧的简介
49 0
|
1月前
|
存储 编译器 Linux
嵌入式C语言(二)
嵌入式C语言(二)
22 0