巩固C语言(十三)----文件重定向 & 静态库和动态库的使用 &sscanf函数

1 输入输出重定向

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<stdlib.h>

void main()
{
	char str[40];
	scanf("%s", str);
	system(str);
}
运行结果:

D:\Study\Data_Structure\传智播客\文件重定向\Debug>1.exe<3.txt>2.txt
其中3.txt文件中中内容为:tasklist & pause

'<'代表向程序1.exe中输入内容,'>'代表将程序的执行结果重定向到2.txt文件中。


2 静态库文件的生成

头文件: 静态库.h 用于函数的声明
void staticLib();
int staticAdd();
源文件: 静态库.c 用于函数的实现
#include<windows.h>
#include"静态库.h"

void staticLib()
{
	MessageBoxA(0, "静态库文件打印内容", "静态库", 0);
}
int staticAdd(int a, int b)
{
	return a + b;
}
打开 项目属性---- 常规---- 配置类型----改为 静态库.lib---- 生成解决方案,即可生成静态库文件 MyLib.lib
注意:静态库不需要导入导出借口,也就是说 不需要定义main函数

3 动态库文件的生成

#include<windows.h>

_declspec(dllexport) void msg()
{
	MessageBoxA(0, "动态库的调用", "动态库", 0);
}

_declspec(dllexport) int add(int a, int b)
{
	return a + b;
}
打开 项目属性---- 常规---- 配置类型----改为 动态库.dll---- 生成解决方案,即可生成静态库文件 动态库.dll
注意:动态库文件也不需要主函数main

4 动态库文件和静态库文件的使用

#include<stdio.h>
#include<stdlib.h>
#include"静态库.h"					//加不加该头文件都可以
#include<windows.h>
#pragma comment(lib, "静态库.lib")	//将静态库文件加载进来

//重定义动态库函数
typedef void(*pmsg)();				//简化函数指针
typedef int(*padd)(int a, int b);

void main()
{
	//静态库文件可以实现文件的私有,每次更新需要重新编译exe,浪费资源。
	//静态库文件的使用
	staticLib();
	printf("result = %d\n", staticAdd(1, 2));
	

	//动态库文件谁都可以用,只要外部接口一样,不用更新exe,更新dll即可,可以实现功能的更新
	//节约计算机资源,需要使用的时候调用,否则释放,动态库可以劫持
	//动态库的使用
	HMODULE mydll = LoadLibraryA("动态库.dll");			//加载动态库,返回一个指针
	if (!mydll)
		printf("动态库加载失败\n");
	else
	{
		pmsg pmsg1;										//定义一个函数指针
		pmsg1 = (pmsg)GetProcAddress(mydll, "msg");		//获取函数地址
		if (pmsg1)
			pmsg1();			//执行函数

		padd padd1;										//定义一个函数指针
		padd1 = (padd)GetProcAddress(mydll, "add");		//获取函数地址
		if (padd1)
			printf("result = %d\n", padd1(1, 3));
	}

	//释放动态库
	FreeLibrary(mydll);					
	
	system("pause");
}

首先需要将动态库和静态文件拷贝到该源文件当前目录下,然后编译成圣可执行文件即可!

5 sscanf函数----你的能量超出你的想象

以下内容来自<http://www.cnblogs.com/gmh915/archive/2009/09/30/1576995.html>

通过学习和使用个人认为,在字符串格式不是很复杂,但是也并不简单的时候用这个函数比较合适,这个尺度就要靠自己把握了,字符串不是很复杂,但自己写个处理的函数比较麻烦,效率也不高,就用这个函数,如果字符串很复杂,那就用正则表达式吧。
不多说了,看看下面这些介绍和列子吧!

函数原型: int sscanf( const char *buffer, const char *format [,argument ] ...);

Each of these functions returns the number of fields successfully converted and assigned; the return value does not include fields that were read but not assigned. A return value of 0 indicates that no fields were assigned. The return value is EOF for an error or if the end of the string is reached before the first conversion.

A format specification has the following form:

%[*] [width] [{h | l | I64 | L}]type

The format argument specifies the interpretation of the input and can contain one or more of the following:

White-space characters: blank (' '); tab ('\t'); or newline ('\n'). A white-space character causes scanf to read, but not store, all consecutive white-space characters in the input up to the next non–white-space character. One white-space character in the format matches any number (including 0) and combination of white-space characters in the input.


Non–white-space characters, except for the percent sign (%). A non–white-space character causes scanf to read, but not store, a matching non–white-space character. If the next character in stdin does not match, scanf terminates.


Format specifications, introduced by the percent sign (%). A format specification causes scanf to read and convert characters in the input into values of a specified type. The value is assigned to an argument in the argument list.
The format is read from left to right. Characters outside format specifications are expected to match the sequence of characters in stdin; the matching characters in stdin are scanned but not stored. If a character in stdin conflicts with the format specification, scanf terminates, and the character is left in stdin as if it had not been read.

When the first format specification is encountered, the value of the first input field is converted according to this specification and stored in the location that is specified by the first argument. The second format specification causes the second input field to be converted and stored in the second argument, and so on through the end of the format string.

An input field is defined as all characters up to the first white-space character (space, tab, or newline), or up to the first character that cannot be converted according to the format specification, or until the field width (if specified) is reached. If there are too many arguments for the given specifications, the extra arguments are evaluated but ignored. The results are unpredictable if there are not enough arguments for the format specification.

Each field of the format specification is a single character or a number signifying a particular format option. The type character, which appears after the last optional format field, determines whether the input field is interpreted as a character, a string, or a number.

The simplest format specification contains only the percent sign and a type character (for example, %s). If a percent sign (%) is followed by a character that has no meaning as a format-control character, that character and the following characters (up to the next percent sign) are treated as an ordinary sequence of characters, that is, a sequence of characters that must match the input. For example, to specify that a percent-sign character is to be input, use %%.

An asterisk (*) following the percent sign suppresses assignment of the next input field, which is interpreted as a field of the specified type. The field is scanned but not stored.

支持集合操作:
%[a-z] 表示匹配a到z中任意字符,贪婪性(尽可能多的匹配)
%[aB'] 匹配a、B、'中一员,贪婪性
%[^a] 匹配非a的任意字符,贪婪性

例子:

1. 常见用法

char buf[512] = { 0 };
sscanf("123456 ", "%s", buf);
printf("%s\n", buf);
结果:123456

2. 取指定长度的字符串

如在下例中,取最大长度为4字节的字符串。 
	char buf[512] = { 0 };
	sscanf("123456 ", "%4s", buf);
	printf("%s\n", buf);
结果:1234

3.取到指定字符为止的字符串

如在下例中,取遇到字符b为止字符串。
	char buf[512] = { 0 };
	sscanf("123456 abcdedf", "%[^b]", buf);
	printf("%s\n", buf);
结果:123456 a

4.取仅包含指定字符集的字符串

如在下例中,取仅包含1到9和小写字母的字符串。
	char buf[512] = { 0 };
	sscanf("123456abcdedfBCDEF", "%[1-9a-z]", buf);
	printf("%s\n", buf);
结果:123456abcdef;  遇到不是中括号中的字符就结束
	char buf[512] = { 0 };
	sscanf("ABC123456abcdedfBCDEF", "%[1-9a-z]", buf);
	printf("%s\n", buf);
结果为空。

5.取到指定字符集为止的字符串

如在下例中,取遇到大写字母为止的字符串。
	char buf[512] = { 0 };
	sscanf("123456abcdedfBCDEF", "%[^A-Z]", buf);
	printf("%s\n", buf);
结果:123456abcdef

6.给定一个字符串,过滤中间的内容

给定一个字符串iios/12DDWDFF@122,获取 / 和 @ 之间的字符串,先将 "iios/"过滤掉,再将非'@'的一串内容送到buf中。
	char buf[512] = { 0 };
	sscanf("iios/12DDWDFF@122", "%*[^/]/%[^@]", buf);
	printf("%s\n", buf);
结果:12DWDFF

7.给定一个字符仅保留特定部分

给定一个字符串““hello, world”,仅保留world。(注意:“,”之后有一空格)
char buf[512] = { 0 };
	sscanf("hello, world", "%*s%s", buf);
	printf("%s\n", buf);
结果:world
%*s表示第一个匹配到的%s被过滤掉,即hello被过滤了
如果没有空格则结果为NULL。

8.非转换字符

	char s1[20], s2[20];
	char *s = "1try234delete5";
	sscanf(s, "1%[^2]234%[^5]", s1, s2);
	printf("s1 = %s\n", s1);
	printf("s2 = %s\n", s2);

结果:
s1 = try
s2 = delete
请按任意键继续. . .
分析:scanf的format中出现的非转换字符(%之前或转换字符之后的字符),即此例中的1234用来跳过输入中的相应字符; 
‘[]’的含义与正则表达式中相同,表示匹配其中出现的字符序列;^表示相反。使用[ ]时接收输入的变量必须是有足够存储空间的char、signed char、unsigned char数组。记住[也是转换字符,所以没有s了。

9.分割以某字符标记的字符串

	char test[] = "222,333,444,555,666,,777888";
	char s1[4] = { 0 }, s2[4] = { 0 }, s3[4] = { 0 }, s4[4] = { 0 }, s5[4] = { 0 }, s6[4] = { 0 }, s7[4] = { 0 };
	sscanf(test, "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,]", s1, s2, s3, s4, s5, s6, s7);
	printf("sssa1=%s\n", s1);
	printf("sssa2=%s\n", s2);
	printf("sssa3=%s\n", s3);
	printf("sssa4=%s\n", s4);
	printf("sssa5=%s\n", s5);
	printf("sssa6=%s\n", s6);
	printf("sssa7=%s\n", s7);
结果:
sssa1=222
sssa2=333
sssa3=444
sssa4=555
sssa5=666
sssa6=
sssa7=
请按任意键继续. . .

10.一个提取用户个人资料中邮件地址的例子

	char a[20] = { 0 };
	char b[20] = { 0 };
	//假设email地址信息以';'结束 
	sscanf("email:[email protected];", "%*[^:]:%[^;]", a);
	//假设email地址信息没有特定的结束标志 
	sscanf("email:[email protected]", "%*[^:]:%s", b);
	printf("%s\n", a);
	printf("%s\n", b);

运行结果:
[email protected]
[email protected]
请按任意键继续. . .
分析:
关键是"%*[^:]:%[^;]"和"%*[^:]:%s"这两个参数的问题 
%*[^:] 表示满足"[]"里的条件将被过滤掉,不会向目标参数中写入值。这里的意思是在 
第一个':'之前的字符会在写入时过滤掉,'^'是表示否定的意思,整个参数翻译 
成白话就是:将在遇到第一个':'之前的(不为':'的)字符全部过滤掉。 
: 自然就是跳过':'的意思。 
%[^;] 拷贝字符直到遇到';'。

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<stdlib.h>

void main1()
{
	printf("main1\n");
	char buf[512] = { 0 };
	sscanf("123456 ", "%s", buf);
	printf("%s\n\n", buf);
}

void main2()
{
	printf("main2\n");
	char buf[512] = { 0 };
	sscanf("123456 ", "%4s", buf);
	printf("%s\n\n", buf);
}

void main3()
{
	printf("main3\n");
	char buf[512] = { 0 };
	sscanf("123456 abcdedf", "%[^b]", buf);
	printf("%s\n\n", buf);
}

void main4()
{
	printf("main4\n");
	char buf[512] = { 0 };
	sscanf("ABC123456abcdedfBCDEF", "%[1-9a-z]", buf);
	printf("%s\n\n", buf);
}

void main5()
{
	printf("main5\n");
	char buf[512] = { 0 };
	sscanf("123456abcdedfBCDEF", "%[^A-Z]", buf);
	printf("%s\n\n", buf);
}

void main6()
{
	printf("main6\n");
	char buf[512] = { 0 };
	sscanf("iios/12DDWDFF@122", "%*[^/]/%[^@]", buf);
	printf("%s\n\n", buf);
}

void main7()
{
	printf("main7\n");
	char buf[512] = { 0 };
	sscanf("hello, world", "%*s%s", buf);
	printf("%s\n\n", buf);
}

void main8()
{
	printf("main8\n");
	char s1[20], s2[20];
	char *s = "1try234delete5";
	sscanf(s, "1%[^2]234%[^5]", s1, s2);
	printf("s1 = %s\n", s1);
	printf("s2 = %s\n\n", s2);
}

void main9()
{
	printf("main9\n");
	char test[] = "222,333,444,555,666,,777888";
	char s1[4] = { 0 }, s2[4] = { 0 }, s3[4] = { 0 }, s4[4] = { 0 }, s5[4] = { 0 }, s6[4] = { 0 }, s7[4] = { 0 };
	sscanf(test, "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,]", s1, s2, s3, s4, s5, s6, s7);
	printf("sssa1=%s\n", s1);
	printf("sssa2=%s\n", s2);
	printf("sssa3=%s\n", s3);
	printf("sssa4=%s\n", s4);
	printf("sssa5=%s\n", s5);
	printf("sssa6=%s\n", s6);
	printf("sssa7=%s\n\n", s7);
}

void main10()
{
	printf("main10\n");
	char a[20] = { 0 };
	char b[20] = { 0 };
	//假设email地址信息以';'结束 
	sscanf("email:[email protected];", "%*[^:]:%[^;]", a);
	//假设email地址信息没有特定的结束标志 
	sscanf("email:[email protected]", "%*[^:]:%s", b);
	printf("%s\n", a);
	printf("%s\n\n", b);
}

void main()
{
	main1();
	main2();
	main3();
	main4();
	main5();
	main6();
	main7();
	main8();
	main9();
	main10();

	system("pause");
}

运行结果:
main1
123456

main2
1234

main3
123456 a

main4


main5
123456abcdedf

main6
12DDWDFF

main7
world

main8
s1 = try
s2 = delete

main9
sssa1=222
sssa2=333
sssa3=444
sssa4=555
sssa5=666
sssa6=
sssa7=

main10
[email protected]
[email protected]

请按任意键继续. . .


总结:

%[ ] 的用法:%[ ]表示要读入一个字符集合, 如果[ 后面第一个字符是”^”,则表示反意思。
[ ]内的字符串可以是1或更多字符组成。空字符集(%[])是违反规定的,可
导致不可预知的结果。%[^]也是违反规定的。 

%[a-z] 读取在 a-z 之间的字符串,如果不在此之前则停止,如
char s[]="hello, my friend” ; // 注意: ,逗号在不 a-z之间
scanf( s, “%[a-z]”, string ) ; // string=hello

%[^a-z] 读取不在 a-z 之间的字符串,如果碰到a-z之间的字符则停止,如
char s[]="HELLOkitty” ; // 注意: ,逗号在不 a-z之间
sscanf( s, “%[^a-z]”, string ) ; // string=HELLO

%*[^=] 前面带 * 号表示不保存变量。跳过符合条件的字符串。
char s[]="notepad=1.0.0.1001" ;
char szfilename [32] = "" ;
int i = sscanf( s, "%*[^=]", szfilename ) ; // szfilename=NULL,因为没保存
int i = sscanf( s, "%*[^=]=%s", szfilename ) ; // szfilename=1.0.0.1001

%40c 读取40个字符

The run-time library does not automatically append a null terminator to the string, nor does reading 40 characters automatically terminate the scanf() function. Because the library uses buffered input, you must press the ENTER keyto terminate the string scan. If you press the ENTER before the scanf() reads 40 characters, it is displayed normally, and the library continues to prompt for additional input until it reads 40 characters

%[^=] 读取字符串直到碰到’=’号,’^’后面可以带更多字符,如:
char s[]="notepad=1.0.0.1001" ;
char szfilename [32] = "" ;
int i = sscanf( s, "%[^=]", szfilename ) ; // szfilename=notepad 
如果参数格式是:%[^=:] ,那么也可以从 notepad:1.0.0.1001读取notepad

使用例子:
char s[]="notepad=1.0.0.1001" ;
char szname [32] = "" ;
char szver [32] = “” ;
sscanf( s, "%[^=]=%s", szname , szver ) ; // szname=notepad, szver=1.0.0.1001
总结:%[]有很大的功能,但是并不是很常用到,主要因为:
1、许多系统的 scanf 函数都有漏洞. (典型的就是 TC 在输入浮点型时有时会出错).
2、用法复杂, 容易出错.
3、编译器作语法分析时会很困难, 从而影响目标代码的质量和执行效率.
个人觉得第3点最致命,越复杂的功能往往执行效率越低下。而一些简单的字符串分析我们可以自已处理。

你可能感兴趣的:(函数,字符串,C语言)