.
作者 : 万境绝尘
转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/21551397 | http://www.hanshuliang.com/?post=29
.
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
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
/*
* 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
#include
#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, 那么就将字符串再输出一遍;
octopus@octopus-Vostro-270s:~/code/c/pointer$ gcc grep.c -o grep
octopus@octopus-Vostro-270s:~/code/c/pointer$ ./grep abc
qwe
asd
zxc
qabc
qabc
wabcc
wabcc
12
要点解析 :
-- 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参数 :
-- 执行(*++argv)[0]表达式 :
-- 执行*++argv[0]表达式 :
代码 :
/*************************************************************************
> File Name: grep_option.c
> Author: octopus
> Mail: octopus_work.163.com
> Created Time: 2014年03月21日 星期五 09时30分07秒
************************************************************************/
#include
#include
#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);
}
}
}
执行结果 :
octopus@octopus-Vostro-270s:~/code/c/pointer$ gcc grep_option.c -o grep
octopus@octopus-Vostro-270s:~/code/c/pointer$ ./grep -xn a
qw
1 : qw
as
qc
3 : qc
octopus@octopus-Vostro-270s:~/code/c/pointer$ ./grep -n a
qw
as
2 : as
qc
octopus@octopus-Vostro-270s:~/code/c/pointer$ ./grep -x a
qw
qw
as
qc
qc
2. 函数指针 和 指针函数
(1) 指针函数
概念 : 函数返回的结果是一个地址, 即返回的是一个指针, 这个函数就是指针函数;
指针函数格式 : 类型说明符 *函数名(参数列表);
-- 示例 : char *getchar(void);
-- 格式说明 : char * 表示函数返回值是指针, 调用这个函数, 返回一个指针指向的char类型;
运算符优先级 : 指针函数有两个运算符 * 和 (), ()的优先级 大于 *, 因此函数名首先和 () 结合, 然后在和 * 结合;
(2) 函数指针概念 : 函数指针指向了函数的地址, 该指针可以调用函数;
函数指针格式 : 类型说明符 (*指针名)(参数列表);
-- 示例 : char (*getcahr)(void);
运算符优先级 : * 和 指针名 先结合, 然后在与参数列表结合;
函数指针使用 :
-- 声明函数指针 : void (*getchar)(), 声明函数指针需要带上参数列表;
-- 为函数指针赋值 : getchar = &get_char 或者 getchar = get_char 两种方法, & 可有可无;
-- 调用函数指针方法 : (*get_char)();
(3) 使用函数指针示例示例需求 :
-- 获取字符串数组 : 从标准输入流中读取字符串数据, 将字符串放入字符串数组 char **;
-- 可选参数 : -n, 如果有可选参数, 就是按照数值顺序排序, 否则按照字典顺序排序;
代码 :
/*************************************************************************
> File Name: method_pointer_sort.c
> Author: octopus
> Mail: octopus_work.163.com
> Created Time: Sat 22 Mar 2014 11:45:47 PM CST
************************************************************************/
#include
#include
#include
//定义排序字符串最大个数
#define MAXLINES 50
//每个字符串最多50个元素
#define MAXLEN 50
//定义一个 有MAXLINES 个 元素的数组, 数组中的元素师字符串, 即char类型指针
char *lineptr[MAXLINES];
/*
* 声明函数指针
*/
int (*p_get_line)(char *, int);
int (*p_read_lines)(char **, int);
void (*p_write_lines)(char **, int);
void (*p_q_sort)(void **, int, int, int (*)(void *, void*));
/*
* 声明函数, 如果直接使用这些函数, 即使函数定义在主函数后面也不会出错
* 如果要将函数赋值给函数指针, 需要提前声明这些函数
*/
int get_line(char *, int);
int read_lines(char **, int);
void write_lines(char **, int);
void q_sort(void *v[], int left, int right, int (*comp)(void *, void *));
int numcmp(char *, char *);
int main(int argc, char **argv)
{
char line[MAXLEN];
int len, nlines, numberic = 0;
p_read_lines = read_lines;
p_write_lines = write_lines;
p_q_sort = q_sort;
//如果参数中含有 -n 说明这是按照数值顺序排序, 否则就按照字典顺序排序
if(argc > 1 && strcmp(argv[1], "-n") == 0)
numberic = 1;
if((nlines = (*p_read_lines)(lineptr, MAXLINES)) >= 0)
{
/*
* 注意 :
* 使用 ? : 表达式选择 函数指针, 函数指针类型转换的时候, 为每个选项都添加转换
* 如果只转换 ? : 结果, 会报出警告
*/
(*p_q_sort)((void **)lineptr, 0, nlines - 1, numberic ? (int (*)(void*, void*))numcmp : (int (*)(void*, void*))strcmp);
(*p_write_lines)(lineptr, nlines);
return 0;
}
else
{
printf("error \n");
return 1;
}
}
//从标准输入流中读取数据, 放入字符串中
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 read_lines(char *lineptr[], int max)
{
int len, nlines = 0;
char *p, line[MAXLEN];
while((len = get_line(line, MAXLEN)) > 0)
{
if(nlines >= MAXLINES || (p = malloc(sizeof(char) * (len + 1))) == NULL)
{
return -1;
}
else
{
strcpy(p, line);
*(lineptr + nlines) = p;
nlines++;
}
}
return nlines;
}
//将字符串数组中的元素打印出来
void write_lines(char *lineptr[], int nlines)
{
int i;
for(i = 0; i < nlines; i++)
{
printf("the %d char sequence is : %s \n", i, *(lineptr + i));
}
}
//数值比较
int numcmp(char *s1, char *s2)
{
double v1, v2;
v1 = atof(s1);
v2 = atof(s2);
if(v1 < v2)
return -1;
else if(v1 > v2)
return 1;
else if(v1 == v2)
return 0;
}
//交换数组中 i j 元素
void swap(void *v[], int i, int j)
{
void *temp;
temp = *(v + i);
*(v + i) = *(v + j);
*(v + j) = temp;
}
//排序方法
void q_sort(void *v[], int left, int right, int (*comp)(void *, void *))
{
int i, last;
if(left >= right)
{
return;
}
swap(v, left, (left + right)/2);
last = left;
for(i = last + 1; i
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?