void *memset(void *s,int c,size_t n)
总的作用:将已开辟内存空间 s 的首 n 个字节的值设为值 c。
例子 :
main(){
char *s="Golden Global View";
clrscr(); //clear screen
memset(s,'G',6);
printf("%s",s);
getchar();
return 0;
}
memset() 函数常用于内存空间初始化。如:
char str[100];
memset(str,0,100);
memset()的深刻内涵:用来对一段内存空间全部设置为某个字符,一般用在对定义的字符串进行初始化为‘ ’或‘/0’;例:char a[100];memset(a, '/0', sizeof(a));
memcpy
用来做内存拷贝,你可以拿它拷贝任何数据类型的对象,可以指定拷贝的数据长度;例:char a[100],b[50]; memcpy(b, a, sizeof(b));注意如用sizeof(a),会造成b的内存地址溢出。
strcpy
就只能拷贝字符串了,它遇到'/0'就结束拷贝;例:char a[100],b[50];strcpy(a,b);如用strcpy(b,a),要注意a中的字符串长度(第一个‘/0’之前)是否超过50位,如超过,则会造成b的内存地址溢出。
函数memset()是针对字节操作的,其中第二个参数值被赋给第一个参数指向的内存地址开始的每一个字节,因此,这种初始化其实存在局限性,也导致其主要用于清除数组内容等。比如:假设i=0,1,2,...
memset(a,0,sizeof(a)); // 此时a[i]=0x00000000
memset(a,-1,sizeof(a)); // 此时a[i]=0xffffffff
memset(a,0x0f,sizeof(a)); // 此时a[i]=0x0f0f0f0f=252645135
由于500=0x1f4,400=0x190,因此,如果使用
memset(a,0x190,sizeof(a)); // 此时a[i]=0x90909090
所以,初始化过程还是建议使用循环语句来做。
memest原型 (please type "man memset" in your shell)
void *memset(void *s, int c, size_t n);
memset:作用是在一段内存块中填充某个给定的值,它对较大的结构体或数组进行清零操作的一种最快方法。
常见的三种错误
第一: 搞反了c 和 n的位置.
一定要记住 如果要把一个char a[20]清零, 一定是 memset(a, 0, 20)
而不是 memset(a, 20, 0)
第二: 过度使用memset, 我想这些程序员可能有某种心理阴影, 他们惧怕未经初始化的内存, 所以他们会写出这样的代码:
char buffer[20];
memset(buffer, 0, sizeof((char)*20));
strcpy(buffer, "123");
这里的memset是多余的. 因为这块内存马上就被覆盖了, 清零没有意义.
第三: 其实这个错误严格来讲不能算用错memset, 但是它经常在使用memset的场合出现
int some_func(struct something *a){
…
…
memset(a, 0, sizeof(a));
…
}
问:为何要用memset置零?memset( &Address, 0, sizeof(Address));经常看到这样的用法,其实不用的话,分配数据的时候,剩余的空间也会置零的。
答:1.如果不清空,可能会在测试当中出现野值。 你做下面的试验看看结果()
char buf[5];
CString str,str1; //memset(buf,0,sizeof(buf)); for(int i = 0;i<5;i++) { str.Format(“%d “,buf[i]); str1 +=str ; } TRACE(“%s/r/n“,str1)
2.其实不然!特别是对于字符指针类型的,剩余的部分通常是不会为0的,不妨作一个试验,定义一个字符数组,并输入一串字符,如果不用memset实现清零,使用MessageBox显示出来就会有乱码(0表示NULL,如果有,就默认字符结束,不会输出后面的乱码)
问:
如下demo是可以的,能把数组中的元素值都设置成字符1,
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char a[5];
memset(a,'1',5);
for(int i = 0;i < 5;i++)
cout<<a[i]<<" ";
system("pause");
return 0;
}
而,如下程序想吧数组中的元素值设置成1,却是不可行的
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
int a[5];
memset(a,1,5);//这里改成memset(a,1,5 *sizeof(int))也是不可以的
for(int i = 0;i < 5;i++)
cout<<a[i]<<" ";
system("pause");
return 0;
}
问题是:
1,第一个程序为什么可以,而第二个不行,
2,不想要用for,或是while循环来初始化int a[5];能做到吗?(有没有一个像memset()这样的函数初始化)
答:
1.因为第一个程序的数组a是字符型的,字符型占据内存大小是1Byte,而memset函数也是以字节为单位进行赋值的,所以你输出没有问题。而第二个程序a是整型的,使用memset还是按字节赋值,这样赋值完以后,每个数组元素的值实际上是0x01010101即十进制的16843009。你看看你输出结果是否这样?
2.如果用memset(a,1,20);
就是对a指向的内存的20个字节进行赋值,每个都用ASCII为1的字符去填充,转为二进制后,1就是00000001,占一个字节。一个INT元素是4字节,合一起就是1000000010000000100000001,就等于16843009,就完成了对一个INT元素的赋值了。
在C/C++语言中使用正则表达式 2009-06-09 09:38:58 www.hackbase.com 来源:互联网
本文所有的内容都来自网络,加上一些个人的理解,不保证正确性,欢迎批评指正,Email/MSN: caijimin@hotmail.com 说起正则表达式(Regular Expression),也许有的朋友天天都在使用,比如grep、vim、sed ...
本文所有的内容都来自网络,加上一些个人的理解,不保证正确性,欢迎批评指正,Email/MSN: caijimin@hotmail.com
说起正则表达式(Regular Expression),也许有的朋友天天都在使用,比如grep、vim、sed、awk,只是可能对这个名词不大熟悉。正则表达式一般简写为regex或者regexp,甚至是RE。关于正则表达式的介绍,有很多的文章,用搜索引擎查找就可以找到很不错的使用说明。但是在C/C++语言中如何去使用,相应的介绍比较缺乏。大多数C标准库自带regex,可以通过/usr/include/regex.h去看,或者man regex看使用说明。perl,php等语言更是提供了功能强大的正则表达式,最著名的C语言正则表达式库为PCRE(Perl Compatible Regular Expression)。本文主要对regex和pcre的使用做一点入门介绍。
1、regex
regex的使用非常简单,只要看一下示例代码1就能明白(示例代码是从“GNU C 规则表达式入门”这篇文章里摘取出来的,是否为原始出处就
不得而知了)。
CODE:#include <stdio.h>
#include <string.h>
#include <regex.h>
#define SUBSLEN 10 /* 匹配子串的数量 */
#define EBUFLEN 128 /* 错误消息buffer长度 */
#define BUFLEN 1024 /* 匹配到的字符串buffer长度 */
int main()
{
size_t len;
regex_t re; /* 存储编译好的正则表达式,正则表达式在使用之前要经过编译 */
regmatch_t subs [SUBSLEN]; /* 存储匹配到的字符串位置 */
char matched [BUFLEN]; /* 存储匹配到的字符串 */
char errbuf [EBUFLEN]; /* 存储错误消息 */
int err, i;
char src [] = "111 <title>Hello World</title> 222"; /* 源字符串 */
char pattern [] = "<title>(.*)</title>"; /* pattern字符串 */
printf("String : %s/n", src);
printf("Pattern: /"%s/"/n", pattern);
/* 编译正则表达式 */
err = regcomp(&re, pattern, REG_EXTENDED);
if (err) {
len = regerror(err, &re, errbuf, sizeof(errbuf));
printf("error: regcomp: %s/n", errbuf);
return 1;
}
printf("Total has subexpression: %d/n", re.re_nsub);
/* 执行模式匹配 */
err = regexec(&re, src, (size_t) SUBSLEN, subs, 0);
if (err == REG_NOMATCH) { /* 没有匹配成功 */
printf("Sorry, no match .../n");
regfree(&re);
return 0;
} else if (err) { /* 其它错误 */
len = regerror(err, &re, errbuf, sizeof(errbuf));
printf("error: regexec: %s/n", errbuf);
return 1;
}
/* 如果不是REG_NOMATCH并且没有其它错误,则模式匹配上 */
printf("/nOK, has matched .../n/n");
for (i = 0; i <= re.re_nsub; i++) {
len = subs[i].rm_eo - subs[i].rm_so;
if (i == 0) {
printf ("begin: %d, len = %d ", subs[i].rm_so, len); /* 注释1 */
} else {
printf("subexpression %d begin: %d, len = %d ", i, subs[i].rm_so, len);
}
memcpy (matched, src + subs[i].rm_so, len);
matched[len] = '/0';
printf("match: %s/n", matched);
}
regfree(&re); /* 用完了别忘了释放 */
return (0);
}
执行结果是
CODE:String : 111 <title>Hello World</title> 222
Pattern: "<title>(.*)</title>"
Total has subexpression: 1
OK, has matched ...
begin: %, len = 4 match: <title>Hello World</title>
subexpression 1 begin: 11, len = 11 match: Hello World
从示例程序可以看出,使用之前先用regcomp()编译一下,然后调用regexec()进行实际匹配。如果只是看有没有匹配成功,掌握这2个函数的用法即可。有时候我们想要取得匹配后的子表达式,比如示例中想获得title是什么,需要用小括号 "( )"把子表达式括起来"<title>(.*)</title>",表达式引擎会将小括号 "( )" 包含的表达式所匹配到的字符串记录下来。在获取匹配结果的时候,小括号包含的表达式所匹配到
的字符串可以单独获取,示例程序就是我用来获取http网页的主题(title)的方式。
regmatch_t subs[SUBSLEN]是用来存放匹配位置的,subs[0]里存放这个匹配的字符串位置,subs[1]里存放第一个子表达式的匹配位置,也就是例子中的title,通过结构里的rm_so和rm_eo可以取到,这一点很多人不太注意,应该强调一下。
注释1:开始调试代码的时候是在FreeBSD 6.2上进行的,print出来的len总是0,但print出来的字符串又没错,很是迷惑,把它放到Linux上则完全正常,后来仔细检查才发现rm_so在Linux上是32位,在FreeBSD上是64位,用%d的话实际取的是rm_so的高32位,而不是实际的len,把print rm_so的地方改为%llu就可以了。
regex虽然简单易用,但对正则表达式的支持不够强大,中文处理也有问题,于是引出了下面要说的PCRE。
2、PCRE (http://www.pcre.org)
PCRE的名字就说明了是Perl Compatible,熟悉Perl、PHP的人使用起来完全没有问题。PCRE有非常丰富的使用说明和示例代码(看看
pcredemo.c就能明白基本的用法),下面的程序只是把上面regex改为pcre。
CODE:/* Compile thuswise:
* gcc -Wall pcre1.c -I/usr/local/include -L/usr/local/lib -R/usr/local/lib -lpcre
*
*/
#include <stdio.h>
#include <string.h>
#include <pcre.h>
#define OVECCOUNT 30 /* should be a multiple of 3 */
#define EBUFLEN 128
#define BUFLEN 1024
int main()
{
pcre *re;
const char *error;
int erroffset;
int ovector[OVECCOUNT];
int rc, i;
char src [] = "111 <title>Hello World</title> 222";
char pattern [] = "<title>(.*)</title>";
printf("String : %s/n", src);
printf("Pattern: /"%s/"/n", pattern);
re = pcre_compile(pattern, 0, &error, &erroffset, NULL);
if (re == NULL) {
printf("PCRE compilation failed at offset %d: %s/n", erroffset, error);
return 1;
}
rc = pcre_exec(re, NULL, src, strlen(src), 0, 0, ovector, OVECCOUNT);
if (rc < 0) {
if (rc == PCRE_ERROR_NOMATCH) printf("Sorry, no match .../n");
else printf("Matching error %d/n", rc);
free(re);
return 1;
}
printf("/nOK, has matched .../n/n");
for (i = 0; i < rc; i++) {
char *substring_start = src + ovector[2*i];
int substring_length = ovector[2*i+1] - ovector[2*i];
printf("%2d: %.*s/n", i, substring_length, substring_start);
}
free(re);
return 0;
}
执行结果是:
CODE:String : 111 <title>Hello World</title> 222
Pattern: "<title>(.*)</title>"
OK, has matched ...
0: <title>Hello World</title>
1: Hello World
比较这2个例子可以看出,在regex用的是regcomp()、regexec(),pcre则使用pcre_compile()、pcre_exec(),用法几乎完全一致。
pcre_compile()有很多选项,详细说明参见http://www.pcre.org/pcre.txt。如果是多行文本,可以设置PCRE_DOTALL的选项pcre_complie(re,
PCRE_DOTALL,....),表示'.'也匹配回车换行"/r/n"。
3、pcre++
pcre++(http://www.daemon.de/PCRE)对pcre做了c++封装,使用起来更加方便。
CODE:/*
* g++ pcre2.cpp -I/usr/local/include -L/usr/local/lib -R/usr/local/lib -lpcre++ -lpcre
*/
#include <string>
#include <iostream>
#include <pcre++.h>
using namespace std;
using namespace pcrepp;
int main()
{
string src("111 <title>Hello World</title> 222");
string pattern("<title>(.*)</title>");
cout << "String : " << src << endl;
cout << "Pattern : " << pattern << endl;
Pcre reg(pattern, PCRE_DOTALL);
if (reg.search(src) == true) { //
cout << "/nOK, has matched .../n/n";
for(int pos = 0; pos < reg.matches(); pos++) {
cout << pos << ": " << reg[pos] << endl;
}
} else {
cout << "Sorry, no match .../n";
return 1;
}
return 0;
}
执行结果是:
CODE:String : 111 <title>Hello World</title> 222
Pattern : <title>(.*)</title>
OK, has matched ...
0: Hello World
4、oniguruma
还有一个正则表达式的库oniguruma(http://www.geocities.jp/kosako3/oniguruma/),对于东亚文字支持比较好,开始是用在ruby上,也可用于C++,是日本的开发人员编写的。大多数人都不会用到,也就不做介绍了。如果有疑问可以通过email来讨论它的用法。
5、Regular Expression的内部实现
关于Regular Expression的实现,用到了不少自动机理论(Automata Theory)的知识,有兴趣的可以找这方面的资料来看,这本书“
Introduction to Automata Theory, Languages, and Computation”写的很好,编译原理的书也有这方面的内容。
本篇文章来源于 黑客基地-全球最大的中文黑客站 原文链接:http://www.hackbase.com/tech/2009-06-09/53155.html
<regex.h>是linux下的一个东西,经过一天的探索,终于找到了在windows下可用的版本:
下载地址如下:http://download.csdn.net/source/1114458
是posix 在win32下regex的库,将.lib文件和.dll文件加放到工程中就可以用了=。=
有问题可以在下面留言
====================================================================================
在GNU C 中要使用规则表达式,需要用到以下几个函数。(定义在/usr/include/regex.h文件中)
int regcomp (regex_t *compiled, const char *pattern, int cflags)
int regexec (regex_t *compiled, char *string, size_t nmatch, regmatch_t matchptr [], int
void regfree (regex_t *compiled)
size_t regerror (int errcode, regex_t *compiled, char *buffer, size_t length)
下面我就介绍分别一下这几个函数和它用到的一些数据类型。
1.int regcomp (regex_t *compiled, const char *pattern, int cflags)
这个函数把指定的规则表达式pattern编译成一种特定的数据格式compiled,这样可以使匹配更有效。函数
regexec 会使用这个数据在目标文
本串中进行模式匹配。执行成功返回0。
regex_t 是一个结构体数据类型,用来存放编译后的规则表达式,它的成员re_nsub 用来存储规则表达式中的子
规则表达式的个数,子规则表
达式就是用圆括号包起来的部分表达式。
pattern 是指向我们写好的规则表达式的指针。
cflags 有如下4个值或者是它们或运算(|)后的值:
REG_EXTENDED 以功能更加强大的扩展规则表达式的方式进行匹配。
REG_ICASE 匹配字母时忽略大小写。
REG_NOSUB 不用存储匹配后的结果。
REG_NEWLINE 识别换行符,这样'$'就可以从行尾开始匹配,'^'就可以从行的开头开始匹配。
2. int regexec (regex_t *compiled, char *string, size_t nmatch, regmatch_t matchptr [], int
eflags)
当我们编译好规则表达式后,就可以用regexec 匹配我们的目标文本串了,如果在编译规则表达式的时候没有指
定cflags的参数为
REG_NEWLINE,则默认情况下是忽略换行符的,也就是把整个文本串当作一个字符串处理。执行成功返回0。
regmatch_t 是一个结构体数据类型,成员rm_so 存放匹配文本串在目标串中的开始位置,rm_eo 存放结束位
置。通常我们以数组的形式定义
一组这样的结构。因为往往我们的规则表达式中还包含子规则表达式。数组0单元存放主规则表达式位置,后边的
单元依次存放子规则表达式位
置。
compiled 是已经用regcomp函数编译好的规则表达式。
string 是目标文本串。
nmatch 是regmatch_t结构体数组的长度。
matchptr regmatch_t类型的结构体数组,存放匹配文本串的位置信息。
eflags 有两个值
REG_NOTBOL 按我的理解是如果指定了这个值,那么'^'就不会从我们的目标串开始匹配。总之我到现在还不是很
明白这个参数的意义,
原文如下:
If this bit is set, then the beginning-of-line operator doesn't match the beginning of the
string (presumably
because it's not the beginning of a line).If not set, then the beginning-of-line operator
does match the beginning
of the string.
REG_NOTEOL 和上边那个作用差不多,不过这个指定结束end of line。
3. void regfree (regex_t *compiled)
当我们使用完编译好的规则表达式后,或者要重新编译其他规则表达式的时候,我们可以用这个函数清空
compiled指向的regex_t结构体的内
容,请记住,如果是重新编译的话,一定要先清空regex_t结构体。
4. size_t regerror (int errcode, regex_t *compiled, char *buffer, size_t length)
当执行regcomp 或者regexec 产生错误的时候,就可以调用这个函数而返回一个包含错误信息的字符串。
errcode 是由regcomp 和 regexec 函数返回的错误代号。
compiled 是已经用regcomp函数编译好的规则表达式,这个值可以为NULL。
buffer 指向用来存放错误信息的字符串的内存空间。
length 指明buffer的长度,如果这个错误信息的长度大于这个值,则regerror 函数会自动截断超出的字符串,
但他仍然会返回完整的字符
串的长度。所以我们可以用如下的方法先得到错误字符串的长度。
size_t length = regerror (errcode, compiled, NULL, 0);
----------------------------------------------------------------------------------------
A simple example:
#include <stdio.h>
#include <string.h>
#include "regex.h"
#pragma comment(lib,"regex.lib")
//#pragma comment(lib,"regex-bcc.lib")
#define SUBSLEN 10
#define EBUFLEN 128
#define BUFLEN 1024
using namespace std;
int main()
{
}
---------------------------------------------------------------------------------