Where there is a dream ,there is hope

  C++博客 :: 首页 :: 联系 :: 聚合  :: 管理
  64 Posts :: 0 Stories :: 8 Comments :: 0 Trackbacks

常用链接

留言簿(1)

我参与的团队

搜索

  •  

最新评论

阅读排行榜

评论排行榜

#

尽管函数指针被广泛用于实现函数回调,但C++还提供了一个重要的实现回调函数的方法,那就是函数对象。函数对象(也称“算符”)是重载了“()”操作符的普通类对象。因此从语法上讲,函数对象与普通的函数行为类似。

        用函数对象代替函数指针有几个优点,首先,因为对象可以在内部修改而不用改动外部接口,因此设计更灵活,更富有弹性。函数对象也具备有存储先前调用结果的数据成员。在使用普通函数时需要将先前调用的结果存储在全程或者本地静态变量中,但是全程或者本地静态变量有某些我们不愿意看到的缺陷。
        其次,在函数对象中编译器能实现内联调用,从而更进一步增强了性能。这在函数指针中几乎是不可能实现的。

下面举例说明如何定义和使用函数对象。首先,声明一个普通的类并重载“()”操作符:

class Negate 
{
public: 
int operator() (int n) { return -n;} 
};

        重载操作语句中,记住第一个圆括弧总是空的,因为它代表重载的操作符名;第二个圆括弧是参数列表。一般在重载操作符时,参数数量是固定的,而重载“()” 操作符时有所不同,它可以有任意多个参数。

        因为在Negate中内建的操作是一元的(只有一个操作数),重载的“()”操作符也只有一个参数。返回类型与参数类型相同-本例中为int。函数返回与参数符号相反的整数。

使用函数对象

        我们现在定义一个叫Callback()的函数来测试函数对象。Callback()有两个参数:一个为int一个是对类Negate的引用。 Callback()将函数对象neg作为一个普通的函数名:

#include <iostream>
using std::cout;

void Callback(int n, Negate & neg) 
{
int val = neg(n); //调用重载的操作符“()” 
cout << val;
}

不要的代码中,注意neg是对象,而不是函数。编译器将语句

int val = neg(n);

转化为

int val = neg.operator()(n);

        通常,函数对象不定义构造函数和析构函数。因此,在创建和销毁过程中就不会发生任何问题。前面曾提到过,编译器能内联重载的操作符代码,所以就避免了与函数调用相关的运行时问题。

为了完成上面个例子,我们用主函数main()实现Callback()的参数传递:

int main() 
{
Callback(5, Negate() ); //输出 -5
}

本例传递整数5和一个临时Negate对象到Callback(),然后程序输出-5。

模板函数对象

        从上面的例子中可以看出,其数据类型被限制在int,而通用性是函数对象的优势之一,如何创建具有通用性的函数对象呢?方法是使用模板,也就是将重载的操作符“()”定义为类成员模板,以便函数对象适用于任何数据类型:如double,_int64或char:

class GenericNegate
{
public: 
template <class T> T operator() (T t) const {return -t;}
};

int main()
{
GenericNegate negate;
cout<< negate(5.3333); // double
cout<< negate(10000000000i64); // __int64
}

如果用普通的回调函数实现上述的灵活性是相当困难的。

标准库中函数对象

        C++标准库定义了几个有用的函数对象,它们可以被放到STL算法中。例如,sort()算法以
判断对象(predicate object)作为其第三个参数。判断对象是一个返回Boolean型结果的
模板化的函数对象。可以向sort()传递greater<>或者less<>来强行实现排序的升序或降序:

#include <functional> // for greater<> and less<>
#include <algorithm> //for sort() 
#include <vector>
using namespace std;

int main()

vector <int> vi;
//..填充向量
sort(vi.begin(), vi.end(), greater<int>() );//降序( descending )
sort(vi.begin(), vi.end(), less<int>() ); //升序 ( ascending )
}

posted @ 2011-06-29 18:10 IT菜鸟 阅读(85) | 评论 (0)编辑 收藏

用C++的stl库,相信大家都有用vector的经历,毕竟vector支持直接下标方式取数据的确方便很多。

但是vector默认是不提供find方法的,所以我们在查找的时候,通常这样写代码:

vector<int> vec;
for(unsigned int i = 0;i<vec.size();++i)
{
    if(vec[i]==xxx)
    {
        break;
    }
}

并不是说提供不了,而是stl库中实际上已经有通用的find函数(不止find……)

可以看一下下面的代码:

int main(int argc,char* argv[])
{
    vector<int> vec;
    vec.push_back(123);
    vec.push_back(456);
    vector<int>::iterator findit = find(vec.begin(),vec.end(),123);
    //vector<int>::iterator findit = find(vec.begin(),vec.end(),111);
    if(findit==vec.end())
    {
        printf("no find\n");
    }
    else
    {
        printf("find[%d]\n",*findit);
    }
    return 0;
}

这样的写法会不会简单很多呢?
需要说明的是,虽然这个通用的find方法也是可以用在map,set等上面的,但是效率会比容器内部的find方法慢很多,所以,除非容器实在是没有提供find方法,否则还是建议不要用公共的这一种。

另外,作为题外话,我们需要注意一下vector的删除(erase)操作。由于vector需要能以下标方式取数据,所以必须时刻保证连续的存储空间,对应于实现上,即,当删除vector中间的一个成员时,这个成员后面的所有成员,会以原顺序向前全部拷贝过来。有兴趣的朋友,可以用这个例子测试一下。
这里起码告诉了我们两件事:

1.vector中一个成员被删除,会导致后面的成员进行copy和析构操作。
2.vector不适合做有大量插入删除操作的容器,因为拷贝内存本身浪费很大

OK,到此为止啦~

posted @ 2011-06-22 15:35 IT菜鸟 阅读(2365) | 评论 (0)编辑 收藏

之前写查找一个VECTOR中保存的一个结构的时候,知道其中的一个数据成员,每次都是遍历一遍,写久了觉得好麻烦,觉得不应该是这样才对。果真在网上找到了这个方法:

用boost::bind,非常简单:

find_if(v.begin(),v.end(),bind(&A::id,_1)==25);


如果需要,下面是完整示例代码:

#include   <algorithm>
#include   <vector>
#include   <boost/bind.hpp>

struct   A
{
    int   id;
};

int   main()
{
    using   namespace   std;
    using   namespace   boost;
    vector <A>   v;
    find_if(v.begin(),v.end(),bind(&A::id,_1)==25);
}

//bind用法



posted @ 2011-06-22 15:34 IT菜鸟 阅读(1757) | 评论 (0)编辑 收藏

// general version
template<class T>
class Compare
{
public:
static bool IsEqual(const T& lh, const T& rh)
{
return lh == rh;
}
};

    这是一个用于比较的类模板,里面可以有多种用于比较的函数, 以IsEqual为例。

    一、特化为绝对类型

    也就是说直接为某个特定类型做特化,这是我们最常见的一种特化方式, 如特化为float, double等

 // specialize for float
template<>
class Compare<float>
{
public:
static bool IsEqual(const float& lh, const float& rh)
{
return abs(lh - rh) < 10e-3;
}
};

// specialize for double
template<>
class Compare<double>
{
public:
static bool IsEqual(const double& lh, const double& rh)
{
return abs(lh - rh) < 10e-6;
}
};

    二、特化为引用,指针类型

    这种特化我最初是在stl源码的的iterator_traits特化中发现的, 如下:

 template <class _Iterator>
struct iterator_traits {
typedef typename _Iterator::iterator_category iterator_category;
typedef typename _Iterator::value_type value_type;
typedef typename _Iterator::difference_type difference_type;
typedef typename _Iterator::pointer pointer;
typedef typename _Iterator::reference reference;
};

// specialize for _Tp*
template <class _Tp>
struct iterator_traits<_Tp*> {
typedef random_access_iterator_tag iterator_category;
typedef _Tp value_type;
typedef ptrdiff_t difference_type;
typedef _Tp* pointer;
typedef _Tp& reference;
};

// specialize for const _Tp*
template <class _Tp>
struct iterator_traits<const _Tp*> {
typedef random_access_iterator_tag iterator_category;
typedef _Tp value_type;
typedef ptrdiff_t difference_type;
typedef const _Tp* pointer;
typedef const _Tp& reference;
};

    当然,除了T*, 我们也可以将T特化为 const T*, T&, const T&等,以下还是以T*为例:
 // specialize for T*
template<class T>
class Compare<T*>
{
public:
static bool IsEqual(const T* lh, const T* rh)
{
return Compare<T>::IsEqual(*lh, *rh);
}
};

    这种特化其实是就不是一种绝对的特化, 它只是对类型做了某些限定,但仍然保留了其一定的模板性,这种特化给我们提供了极大的方便, 如这里, 我们就不需要对int*, float*, double*等等类型分别做特化了。

    三、特化为另外一个类模板

    这其实是第二种方式的扩展,其实也是对类型做了某种限定,而不是绝对化为某个具体类型,如下:
 // specialize for vector<T>
template<class T>
class Compare<vector<T> >
{
public:
static bool IsEqual(const vector<T>& lh, const vector<T>& rh)
{
if(lh.size() != rh.size()) return false;
else
{
for(int i = 0; i < lh.size(); ++i)
{
if(lh[i] != rh[i]) return false;
}
}
return true;
}
};

    这就把IsEqual的参数限定为一种vector类型, 但具体是vector<int>还是vector<float>, 我们可以不关心, 因为对于这两种类型,我们的处理方式是一样的,我们可以把这种方式称为“半特化”。

    当然, 我们可以将其“半特化”为任何我们自定义的模板类类型:
 // specialize for any template class type
template <class T1>
struct SpecializedType
{
T1 x1;
T1 x2;
};
template <class T>
class Compare<SpecializedType<T> >
{
public:
static bool IsEqual(const SpecializedType<T>& lh, const SpecializedType<T>& rh)
{
return Compare<T>::IsEqual(lh.x1 + lh.x2, rh.x1 + rh.x2);
}
};

    这就是三种类型的模板特化, 我们可以这么使用这个Compare类:

 // int
int i1 = 10;
int i2 = 10;
bool r1 = Compare<int>::IsEqual(i1, i2);

// float
float f1 = 10;
float f2 = 10;
bool r2 = Compare<float>::IsEqual(f1, f2);

// double
double d1 = 10;
double d2 = 10;
bool r3 = Compare<double>::IsEqual(d1, d2);

// pointer
int* p1 = &i1;
int* p2 = &i2;
bool r4 = Compare<int*>::IsEqual(p1, p2);

// vector<T>
vector<int> v1;
v1.push_back(1);
v1.push_back(2);

vector<int> v2;
v2.push_back(1);
v2.push_back(2);
bool r5 = Compare<vector<int> >::IsEqual(v1, v2);

// custom template class
SpecializedType<float> s1 = {10.1f,10.2f};
SpecializedType<float> s2 = {10.3f,10.0f};
bool r6 = Compare<SpecializedType<float> >::IsEqual(s1, s2);


    模板有两种特化,全特化和偏特化(局部特化)

    模板函数只能全特化,没有偏特化(以后可能有)。

    模板类是可以全特化和偏特化的。

    全特化,就是模板中模板参数全被指定为确定的类型。

    全特化也就是定义了一个全新的类型,全特化的类中的函数可以与模板类不一样。

    偏特化,就是模板中的模板参数没有被全部确定,需要编译器在编译时进行确定。

    在类型上加上const、&、*( cosnt int、int&、int*、等等)并没有产生新的类型。只是类型被修饰了。模板在编译时,可以得到这些修饰信息。

    模板的特化是非常有用的。它像一个在编译期的条件判断。当编译器在编译时找到了符合的特化实现,就会使用这个特化实现。这就叫编译器多态(或者叫静态多态)。这种东西对编写基础库是很有用的。这也就是为何c++的基础库大量使用了模板技术,而且大量使用了特化,特别是偏特化。

    在泛型中,利用特化类得到类新的特性,以便找到最适合这种特性的实现。而这一切都是在编译时完成。

posted @ 2011-06-16 18:26 IT菜鸟 阅读(503) | 评论 (0)编辑 收藏

C++箴言:理解typename的两个含义  问题:在下面的 template declarations(模板声明)中 class 和 typename 有什么不同?
template<class T> class Widget; // uses "class"
template<typename T> class Widget; // uses "typename"
  答案:没什么不同。在声明一个 template type parameter(模板类型参数)的时候,class 和 typename 意味着完全相同的东西。一些程序员更喜欢在所有的时间都用 class,因为它更容易输入。其他人(包括我本人)更喜欢 typename,因为它暗示着这个参数不必要是一个 class type(类类型)。少数开发者在任何类型都被允许的时候使用 typename,而把 class 保留给仅接受 user-defined types(用户定义类型)的场合。但是从 C++ 的观点看,class 和 typename 在声明一个 template parameter(模板参数)时意味着完全相同的东西。

  然而,C++ 并不总是把 class 和 typename 视为等同的东西。有时你必须使用 typename。为了理解这一点,我们不得不讨论你会在一个 template(模板)中涉及到的两种名字。

  假设我们有一个函数的模板,它能取得一个 STL-compatible container(STL 兼容容器)中持有的能赋值给 ints 的对象。进一步假设这个函数只是简单地打印它的第二个元素的值。它是一个用糊涂的方法实现的糊涂的函数,而且就像我下面写的,它甚至不能编译,但是请将这些事先放在一边——有一种方法能发现我的愚蠢:
template<typename C> // print 2nd element in
void print2nd(const C& container) // container;

 
// this is not valid C++!
 if (container.size() >= 2{
  C::const_iterator iter(container.begin()); 
// get iterator to 1st element
  ++iter; // move iter to 2nd element
  int value = *iter; // copy that element to an int
  std::cout << value; // print the int
 }

}
  我突出了这个函数中的两个 local variables(局部变量),iter 和 value。iter 的类型是 C::const_iterator,一个依赖于 template parameter(模板参数)C 的类型。一个 template(模板)中的依赖于一个 template parameter(模板参数)的名字被称为 dependent names(依赖名字)。当一个 dependent names(依赖名字)嵌套在一个 class(类)的内部时,我称它为 nested dependent name(嵌套依赖名字)。C::const_iterator 是一个 nested dependent name(嵌套依赖名字)。实际上,它是一个 nested dependent type name(嵌套依赖类型名),也就是说,一个涉及到一个 type(类型)的 nested dependent name(嵌套依赖名字)。

  print2nd 中的另一个 local variable(局部变量)value 具有 int 类型。int 是一个不依赖于任何 template parameter(模板参数)的名字。这样的名字以 non-dependent names(非依赖名字)闻名。(我想不通为什么他们不称它为 independent names(无依赖名字)。如果,像我一样,你发现术语 "non-dependent" 是一个令人厌恶的东西,你就和我产生了共鸣,但是 "non-dependent" 就是这类名字的术语,所以,像我一样,转转眼睛放弃你的自我主张。)

  nested dependent name(嵌套依赖名字)会导致解析困难。例如,假设我们更加愚蠢地以这种方法开始 print2nd:
template<typename C>
void print2nd(const C& container)
{
 C::const_iterator 
* x;
 
//
}
  这看上去好像是我们将 x 声明为一个指向 C::const_iterator 的 local variable(局部变量)。但是它看上去如此仅仅是因为我们知道 C::const_iterator 是一个 type(类型)。但是如果 C::const_iterator 不是一个 type(类型)呢?如果 C 有一个 static data member(静态数据成员)碰巧就叫做 const_iterator 呢?再如果 x 碰巧是一个 global variable(全局变量)的名字呢?在这种情况下,上面的代码就不是声明一个 local variable(局部变量),而是成为 C::const_iterator 乘以 x!当然,这听起来有些愚蠢,但它是可能的,而编写 C++ 解析器的人必须考虑所有可能的输入,甚至是愚蠢的。

  直到 C 成为已知之前,没有任何办法知道 C::const_iterator 到底是不是一个 type(类型),而当 template(模板)print2nd 被解析的时候,C 还不是已知的。C++ 有一条规则解决这个歧义:如果解析器在一个 template(模板)中遇到一个 nested dependent name(嵌套依赖名字),它假定那个名字不是一个 type(类型),除非你用其它方式告诉它。缺省情况下,nested dependent name(嵌套依赖名字)不是 types(类型)。(对于这条规则有一个例外,我待会儿告诉你。)

  记住这个,再看看 print2nd 的开头:
template<typename C>
void print2nd(const C& container)
{
 
if (container.size() >= 2) {
  C::const_iterator iter(container.begin()); 
// this name is assumed to
   // not be a type
  这为什么不是合法的 C++ 现在应该很清楚了。iter 的 declaration(声明)仅仅在 C::const_iterator 是一个 type(类型)时才有意义,但是我们没有告诉 C++ 它是,而 C++ 就假定它不是。要想转变这个形势,我们必须告诉 C++ C::const_iterator 是一个 type(类型)。我们将 typename 放在紧挨着它的前面来做到这一点:
template<typename C> // this is valid C++
void print2nd(const C& container)
{
if (container.size() >= 2) {
typename C::const_iterator iter(container.begin());

}
}
  通用的规则很简单:在你涉及到一个在 template(模板)中的 nested dependent type name(嵌套依赖类型名)的任何时候,你必须把单词 typename 放在紧挨着它的前面。(重申一下,我待会儿要描述一个例外。)

  typename 应该仅仅被用于标识 nested dependent type name(嵌套依赖类型名);其它名字不应该用它。例如,这是一个取得一个 container(容器)和这个 container(容器)中的一个 iterator(迭代器)的 function template(函数模板):
template<typename C> // typename allowed (as is "class")
void f(const C& container, // typename not allowed
typename C::iterator iter); // typename required
  C 不是一个 nested dependent type name(嵌套依赖类型名)(它不是嵌套在依赖于一个 template parameter(模板参数)的什么东西内部的),所以在声明 container 时它不必被 typename 前置,但是 C::iterator 是一个 nested dependent type name(嵌套依赖类型名),所以它必需被 typename 前置。

  "typename must precede nested dependent type names"(“typename 必须前置于嵌套依赖类型名”)规则的例外是 typename 不必前置于在一个 list of base classes(基类列表)中的或者在一个 member initialization list(成员初始化列表)中作为一个 base classes identifier(基类标识符)的 nested dependent type name(嵌套依赖类型名)。例如:
template<typename T>
class Derived: public Base<T>::Nested { 
 
// base class list: typename not
 public// allowed
  explicit Derived(int x)
  : Base
<T>::Nested(x) // base class identifier in mem
  { 
   
// init. list: typename not allowed
 
   typename Base
<T>::Nested temp; // use of nested dependent type
    // name not in a base class list or
  } // as a base class identifier in a
   // mem. init. list: typename required
};
  这样的矛盾很令人讨厌,但是一旦你在经历中获得一点经验,你几乎不会在意它。

  让我们来看最后一个 typename 的例子,因为它在你看到的真实代码中具有代表性。假设我们在写一个取得一个 iterator(迭代器)的 function template(函数模板),而且我们要做一个 iterator(迭代器)指向的 object(对象)的局部拷贝 temp,我们可以这样做:
template<typename IterT>
void workWithIterator(IterT iter)
{
 typename std::iterator_traits
<IterT>::value_type temp(*iter);
 
}
  不要让 std::iterator_traits<IterT>::value_type 吓倒你。那仅仅是一个 standard traits class(标准特性类)的使用,用 C++ 的说法就是 "the type of thing pointed to by objects of type IterT"(“被类型为 IterT 的对象所指向的东西的类型”)。这个语句声明了一个与 IterT objects 所指向的东西类型相同的 local variable(局部变量)(temp),而且用 iter 所指向的 object(对象)对 temp 进行了初始化。如果 IterT 是 vector<int>::iterator,temp 就是 int 类型。如果 IterT 是 list<string>::iterator,temp 就是 string 类型。因为 std::iterator_traits<IterT>::value_type 是一个 nested dependent type name(嵌套依赖类型名)(value_type 嵌套在 iterator_traits<IterT> 内部,而且 IterT 是一个 template parameter(模板参数)),我们必须让它被 typename 前置。

  如果你觉得读 std::iterator_traits<IterT>::value_type 令人讨厌,就想象那个与它相同的东西来代表它。如果你像大多数程序员,对多次输入它感到恐惧,那么你就需要创建一个 typedef。对于像 value_type 这样的 traits member names(特性成员名),一个通用的惯例是 typedef name 与 traits member name 相同,所以这样的一个 local typedef 通常定义成这样:
template<typename IterT>
void workWithIterator(IterT iter)
{
 typedef typename std::iterator_traits
<IterT>::value_type value_type;

 value_type temp(
*iter);
 
}
  很多程序员最初发现 "typedef typename" 并列不太和谐,但它是涉及 nested dependent type names(嵌套依赖类型名)规则的一个合理的附带结果。你会相当快地习惯它。你毕竟有着强大的动机。你输入 typename std::iterator_traits<IterT>::value_type 需要多少时间?

  作为结束语,我应该提及编译器与编译器之间对围绕 typename 的规则的执行情况的不同。一些编译器接受必需 typename 时它却缺失的代码;一些编译器接受不许 typename 时它却存在的代码;还有少数的(通常是老旧的)会拒绝 typename 出现在它必需出现的地方。这就意味着 typename 和 nested dependent type names(嵌套依赖类型名)的交互作用会导致一些轻微的可移植性问题。

  Things to Remember

  ·在声明 template parameters(模板参数)时,class 和 typename 是可互换的。

  ·用 typename 去标识 nested dependent type names(嵌套依赖类型名),在 base class lists(基类列表)中或在一个 member initialization list(成员初始化列表)中作为一个 base class identifier(基类标识符)时除外
posted @ 2011-06-16 10:29 IT菜鸟 阅读(100) | 评论 (0)编辑 收藏

上层涉及到网络消息时,多线程的问题需要时时注意。OnRecvOnClose等消息的调用是在网络线程中,而不是逻辑线程;如果需要在处理网络消息时进行逻辑操作,就一定要对多个线程都涉及到的变量加锁。在逻辑复杂的环境(如逻辑服务器),把所有变量加锁是不现实的,较简单的一种解决方法是把网络消息缓存起来,然后在逻辑线程的定时更新函数里处理这些缓存的消息。这样,需要加锁的只有这个缓存
(待续)
posted @ 2011-04-18 09:53 IT菜鸟 阅读(169) | 评论 (0)编辑 收藏

新公司没有WIKI,只有项目管理的redmine,所以想记录点东西还比较麻烦,所以我决定在自己的机器上配置一下PHP的环境,装上WORDPRESS,充当WIKI用。而且导入导出也很方便,省掉了因为网络不好写blog的窝火和闹心。

1.apache安装,没啥说的 一路NEXT就可以了。
2..php安装,选择版本的时候要注意下
VC6 版本是使用 Visual Studio 6 编译器编译的,如果你是在windows下使用Apache+PHP的,请选择VC6版本
VC9 版本是使用 Visual Studio 2008 编译器编译的,如果你是在windows下使用IIS+PHP的,请选择VC9版本
所以选择VC6的版本

3.关键是两个配置php.ini 和httpd.conf

httpd.conf
1.DocumentRoot(网站的根目录)改成自己的,注意 "\"要改成 "/"
2.DirectoryIndex(目录索引) 添加index.php
3.LoadModule php5_module G:/WEB/php/php5apache2_2.dll
   PHPIniDir "G:/WEB/php"
4.AddType application/x-httpd-php .php AddType application/x-httpd-php .html

php.ini
1.extension:mysql前面的分号去掉
2.d:/php d:/php/ext 目录添加到环境变量里

MySql如果之前有装过的话,可能会出现问题cannot create windows service for mysql.error:0
这样只需要删除MYSQL服务
cmd下:执行 sc delete mysql
也可以把MySql的服务名该一下也OK
posted @ 2011-04-09 13:20 IT菜鸟 阅读(137) | 评论 (0)编辑 收藏

 http://blog.163.com/liuyuelin007@126/blog/static/213387692007411151568/

http://blog.csdn.net/lychee007/archive/2009/05/31/4227419.aspx

http://social.microsoft.com/Forums/es-ES/visualcpluszhchs/thread/ff6ddac2-a69d-4c02-ad20-d73cb4335c24

http://hi.baidu.com/237rxd/blog/item/35a51efa18e098859e5146b9.html

http://topic.csdn.net/t/20050712/20/4140158.html
posted @ 2011-03-20 18:17 IT菜鸟 阅读(366) | 评论 (0)编辑 收藏

     摘要: 看到首页上有人写,自己也写了一个名字起错了,其实写个stack更合适 //!Node information//!struct Node{    int serialNumber;    int flag;    struct ...  阅读全文
posted @ 2011-03-16 10:58 IT菜鸟 阅读(315) | 评论 (1)编辑 收藏

不少笔试题都把这三个函数放一起比较,其实他们三个没啥可比性,就是三个不同的函数而已

Memset 用来对一段内存空间全部设置为某个字符,一般用在对定义的字符串进行初始化为‘ ’‘\0’

主要应用是初始化某个内存空间

:char a[100];memset(a, '\0', sizeof(a));

memset可以方便的清空一个结构类型的变量或数组。

如:

struct sample_struct
{
 char   csName[16];
 int    iSeq;
 int    iType;
};

对于变量
struct sample_strcut  stTest;

一般情况下,清空stTest的方法:

stTest.csName[0]='\0';
stTest.iSeq=0;
stTest.iType=0;

memset就非常方便:
memset(&stTest,0,sizeof(struct sample_struct));

如果是数组:

 struct sample_struct   TEST[10];

memset(TEST,0,sizeof(struct sample_struct)*10);

memcpy 用来做内存拷贝,你可以拿它拷贝任何数据类型的对象,可以指定拷贝的数据长度。

memcpy是用于copy源空间的数据到目的空间中
例:
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的内存地址溢出。


strcpy用于字符串copy,遇到‘\0’,将结束

posted @ 2011-03-15 08:06 IT菜鸟 阅读(296) | 评论 (0)编辑 收藏

仅列出标题
共7页: 1 2 3 4 5 6 7