2016年5月28日

好久不来cppblog,为什么现在网站人气如此凋零!难道c++真的要灭亡了吗?

好久没有来这网站了,为什么现在人气如此凋零了?
每个分区一天下来都几乎没有人发表文章,看首页的排行榜每个月人气最旺的文章也只不过有1000多点的点击量,记得当年火爆的时候随便一个文章累积下来都能有几千的点击量了。
到底发生了什么?难道说C++真的要灭亡了吗?

posted @ 2016-05-28 01:48 古月 阅读(278) | 评论 (0)编辑 收藏

2016年5月27日

输入输出缓冲区和流的概念理解

(本文章关于缓冲区概念的理解大部分取自:http://developer.51cto.com/art/201107/277186.htm

快递的寄送过程:

源地址(商家的仓库)——中转地(快递公司的仓库)——目的地(买家)

我们从淘宝商家买衣服,商家通过快递公司把商品送到我们手里的这个过程可以形象的解释下缓存区和流的这个概念。

1, 淘宝商家不会亲自把商品给买家送过来的,因为这样效率太低了,商家会通过快递公司这个中转,然后快递公司再把东西送给买家。淘宝商家就是在键盘上打字,买家就是程序,程序需要读取从键盘上的输入的字,缓冲区就是快递公司的仓库。

2, 商品的几种位置状态:商家仓库,快递仓库,买家手中,还有一种状态就是在路上。输入输出的流就是指的在路上。

3, 快递收货员收到商品就放到自己的中转仓库中。但是快递公司肯定等仓库中的商品积累到一定程度才开始派送。行缓冲就是遇到换行符时就认为需要执行I/O操作了。


      一,缓冲区的概念

缓冲区又可以称为缓存。计算机中的内存可以被认为是硬盘的缓存。当cpu读取文件、执行程序时,不会直接从硬盘中读取,而是先把文件缓存到内存中,然后再从内存中读取。

对于C++程序来说,当类似cingetchar这样的对象或者函数读取输入时,不会直接直接读键盘上的输入,而是这样的一个过程:cin——输入缓冲区——键盘。我们从键盘上输入的字符先存到缓冲区里面,cin从缓冲区里面读取输入。对于输出来说,程序的结果不会直接显示到屏幕上,而是先存放到缓冲区,然后cout把内容从缓冲区输出到屏幕。cincout本质上都是对缓冲区中的内容进行操作。

如果没有缓冲区就会大大降低CPU的效率,因为cpu将不得不一直等待用户的输入,而不能执行其他的操作,人打字输入的速度再快,也比不上CPU的执行速度,人在输入两个字符之间的间隔时间,cpu完全可以去干别的事情。

缓冲区分为三种全缓冲、行缓冲和不带缓冲。

1、全缓冲

在这种情况下,当填满标准I/O缓存后才进行实际I/O操作。全缓冲的典型代表是对磁盘文件的读写。

2、行缓冲

在这种情况下,当在输入和输出中遇到换行符时,执行真正的I/O操作。这时,我们输入的字符先存放在缓冲区,等按下回车键换行时才进行实际的I/O操作。典型代表是键盘输入数据。

3、不带缓冲

也就是不进行缓冲,标准出错情况stderr是典型代表,这使得出错信息可以直接尽快地显示出来。

缓冲区的刷新指的是缓冲区的内容被清空刷新,这也就意味着刷新之前系统会对缓冲区内容进行I/O读写。下面4种情况会触发缓冲区的刷新:

缓冲区满时;

执行flush语句;

执行endl语句;

关闭文件。

C/C++程序里面的缓冲区指的是为标准输入与标准输出设置的缓冲区,如果我们不认为的设置的话,系统会自动的为标准输入与标准输入设置一个缓冲区,这个缓冲区的大小通常是4Kb的大小。

ANSI C要求下列缓存特征:

(1) 当且仅当标准输入和标准输出并不涉及交互作用设备(键盘,屏幕)时,它们才是全缓存的。 读写文件的时候就是全缓存。

(2)标准出错决不会是全缓存的。

(3)标准输入和输出涉及交互作用设备时,虽然没有明确规定是不带缓存的还是行缓存的,但一般系统默认它们是行缓存的。

 因此我们经常要用的标准输入和输出,stdinstdoutstderr的缓存特征是:stdinstdout是行缓存;而stderr是无缓存的。cincout都是从缓冲区读取

 

 

 

二、流的概念

流是一个过程,一个动态的概念。可以把流想象成水在水管中流动的过程,想象成商品快递运送的过程。Cincout就是执行流这个过程的人。

对于输入,cin负责把输入缓冲区中的内容传递给程序;

对于输出,cout负责把输出缓冲区中的内容传递给屏幕。

Cincout把缓冲区的数据变成流,然后搬运到相应的目的地。Cincout就是个搬运工,搬运的过程就是流。


      三、代码案例
      第一段代码:

int main()
{
    string str;
    int i=0;
    while (cin >> str)
    {
        cout << str<<endl;
        cout << ++i << endl;
    }
    return 0;
}
程序执行过程中输入:i love you
最终结果是:
i
1
love
2
you
3

执行过程中,程序并不会在每次输入一个空格时就打印一次,而在在完全输入一行字符串并摁下回车后,才会打印。原因就是在我们输入回车之前的一行字符串都只是存放到了为标准输入分配的缓冲区中,这是一个行缓冲区,在遇到换行符之前,缓冲区不会刷新也就不会触发I/O操作,cin也就没有在读取数据。输入回车后,cin开始执行I/O操作,读取缓冲区中的字符:首先读取i,然后遇到了空格,此次读取完成,执行循环。然后接着读取love,又遇到了空格,读取完成,执行循环。最后读取了you。
第二段代码:

int main()
{
    char c;
    //第一次调用getchar()函数  
    
//程序执行时,您可以输入一串字符并按下回车键,按下回车键后该函数才返回  
    c = getchar();
    //显示getchar()函数的返回值  
    cout << c << endl;
    //暂停  
    system("PAUSE");
    //循环多次调用getchar()函数  
    
//将每次调用getchar()函数的返回值显示出来  
    
//直到遇到回车符才结束  
    while ((c = getchar()) != '\n')
    {
        printf("%c", c);
    }
    //暂停  
    system("PAUSE");
    return 0;
}
执行程序,输入:abcdefg,然后回车
程序结果如下:
a
bcdefg

第一次执行到getchar时,由于此时缓冲区里面没有任何内容,所以程序等待键盘的输入,输入abcdefg后,然后输入回车,触发了行缓冲的条件,执行I/O,getchar开始读取缓冲区的内容,由于此函数只读取一个字符,所以读完字符a后,读取结束,执行下面的语句,将a打印到屏幕。由于缓冲区中字符只被读取了1个字符a,剩余的bcdefg还在缓冲区中,因此执行到while中的getchar时,直接读取缓冲区中的内容,也就是依次读取bcdefg,回车符也是缓冲区中的一个字符,当读取完回车后,while循环结束。


posted @ 2016-05-27 16:10 古月 阅读(1731) | 评论 (0)编辑 收藏

2014年7月2日

最近很火的50只狗,有好狗有病狗,去判断有几只病狗的的逻辑推理题目

题目:50人有50条狗,有病狗。每个人只能看到其他人的狗(不能看到自己的狗),只有狗的主人才能打死狗。相互不能交流,不能通知狗的主人。如果推断出自家狗是病狗,就要枪毙,只能枪毙自家狗。第一天没有枪声,第二天有一阵枪声。请问有几只病狗?

听说这是小升初的考试题,这实在是太难了,怀疑那些出题的老师第一次看到这个题能不能做出来。这应该是离散数学中典型的逻辑分析题,我想除了专门修过离散数学和少数天才外应该很少有人在规定时间内算出答案,反正我算不出。下面的分析过程,是我参考了网上的答案,再按照自己的理解写出来的。


其实我认为这个题之所以难,我觉得是题目表达的不够清晰。理解这个问题首先有几个隐含的条件要搞明白。
a50只狗里面至少有1只病狗。
b、病狗是一眼就能分辨出来的,但是狗的主人无法观察判断自己的狗是不是病狗。
c、狗的主人推断出自己的狗是病狗后,一定要在当天杀死狗,在当天中的0:0024:00任何时候都行。

从而还能得到一个推论d:如果病狗的主人看到N只病狗,那么好狗的主人能看到N+1只病狗,也就是说病狗的主人看到的病狗的数量是实际病狗数量再减1.


明确了上述的3个条件和1个结论,再去解答这个问题,就会简单很多。 

1, 假设只有1只病狗,所有人在观察完其他人的狗后,那么根据推论d,病狗的主人不会看到病狗,再根据条件a,从而能够推断出自己的狗是病狗,于是会在当天24点之前杀死自己的狗。

2, 但是第一天没有枪声,说明至少有2只病狗(把这个结果当成推论e)。于是从第二天0:00开始,所有人都应该知道至少有两只病狗。假设只有2只病狗,根据推论d,病狗的主人只看到1只病狗,说明剩下的那只没有看到的病狗就是自己的狗,于是在第二天可以从0:0024:00选择任何一个时间点杀死自己的狗,第二天就会听到枪声。

3, 继续假设有3只病狗的话。由根据推论d,病狗的主人能观察到2只病狗,再根据推论e,所以无法判断自己的狗是否为病狗,所以在第二天不可能杀狗,也就不会有枪声,综合12,答案为2只狗。

4, 把题目改一下,改成是第三天听到枪声。第二天0:00一到,大家都知道有2只病狗了,那么第二天一直到24:00都没有枪声的话,说明每个人都看到至少2只病狗。根据推论d,那么从第三天0:00开始,每个人会知道至少有3只病狗。假设也只有3只病狗,那么病狗的主人只能看到2只病狗,说明剩下的那只没有看到的病狗就是自己的狗,于是在第三天肯定要杀死自己的狗,第三天就会有枪声。

5, 以此类推,第几天听到枪声,就有几只狗。

posted @ 2014-07-02 16:06 古月 阅读(13094) | 评论 (11)编辑 收藏

2012年9月26日

用数学来推导趣味逻辑题:骑士与流氓问题。

对于类似骑士与流氓的这种逻辑思维题,除了极个别的天才能够大脑随便一想就知道答案,绝大多数人都要好好的推断一会。
离散数学就教给了我们一种用数学方法来推导这种逻辑题,使得这些问题的难度降低不少。
下面就来看下《离散数学及其应用》第六版,1.1章练习题第55题我的推导分析吧。

一个小岛上住着两类人,一类是骑士,一类是流氓,骑士只说真话,流氓只说假话,有AB两个人,根据他们所说的话,判断AB各自是流氓还是骑士。
a)A说:我们之间至少有一个是流氓。B什么都没有说
b)A说:我们两个都是骑士。B说:A是流氓。
c)A说:我是流氓或者B是骑士。B什么都没说
d)两个人都说:我是骑士
e)A说:我们都是流氓。B什么都没说。

个人分析:
首先,定义命题p为A是骑士,!p代表A是流氓,q为B是骑士,!q为B是流氓
a)A说的内容可以用如下数学符号表达:(!p ∨ !q)。
      假设A是骑士,即p=1,说明A说的内容为真,即(!p ∨ !q)=1,因为p=1推出!p=0,所以!q=1,所有q=0,即B为流氓。过程没有矛盾。
      保险起见,再假设A是流氓,即!p=1,说明A说的内容为假,即(!p ∨ !q)=0,但是!p=1,所以(!p ∨ !q)不可能为0,所以有矛盾。
      结果就是A是骑士,B为流氓
b)A说的内容:(p ∧ q),B说的内容:!p
      假设A是骑士,即p=1,说明A说的内容为真,即(p ∧ q)=1,推出q=1,说明B也为骑士,那B说的话为真,就是说!p=1,即A为流氓,结论与条件矛盾,假设不对
      假设A是流氓,即!p=1,说明A说的内容为假,即(p ∧ q)=0,此时q是0还是1,都符合。再从B说的话着手,因为!p=1,所以B说的话是正确的,所以q=1,B是骑士,没有矛盾。
      结果就是A是流氓,B是骑士
c)A说的内容:(!p ∨ q)
      假设A是骑士,即p=1,说明A说的内容为真,即(!p ∨ q)=1,推出q=1,即说明B也为骑士,没有矛盾。
      假设A不是骑士,即!p=1,说明A说的内容为假,即(!p ∨ q)=0,但是!p=1,所以无论(!p ∨ q)是不可能为0的,所以矛盾
      结果俩人都是骑士
d)A说的内容:p。B说的内容:q
      假设A是骑士,即p=1,说明A说的内容为真,即p=1,与条件相符。
      假设A是流氓,即!p=1,说明A说的内容为假,即p=0,此时也与条件相符。
      B的判断也一样,所以结果是无法判断出谁是骑士谁是流氓
e)A说的内容:(!p ∧ !q)
      假设A是骑士,即p=1,说明A说的内容为真,即(!p ∧ !q)=1,因为!p=0,所以无论如何(!p ∧ !q)是不可能为0的,矛盾
      假设A是流氓,即!p=1,说明A说都内容为假,即(!p ∧ !q)=0,说明!q=0,即B是骑士,没有矛盾
      结果是A是流氓,B是骑士

posted @ 2012-09-26 18:06 古月 阅读(5288) | 评论 (3)编辑 收藏

逻辑推理:在一个100条语句的列表中,第n条语句是“在这个列表中,恰有n条语句为假”,可以得出什么结论?

《离散数学及其应用》第六版1.1练习题第43题的个人分析
题目:在一个100条语句的列表中,第n条语句是“在这个列表中,恰有n条语句为假”..........
     a)从这些语句中得出什么结论
     b) 若第n条语句是”至少有n条语句为家“,结论是什么
     c)假设包含99条语句,回答b

答案网上都有,我是给出自己的分析过程:(思路大概是:如果这句话话为真,推出这句话的内容为真,由这句话的内容又能推出其余话的是不是为真,再根据其余话的内容来判断是不是矛盾。主要就是看这句话为真与这句话的内容为真是不是矛盾。分清这句话和这句话的内容,就明了了)
a)p1,p2,.....p100分别代表这个100条语句。
假设p1为真,根据p1的内容,既然只有1个语句为假了,那后面的99条语句说的全不是只有1个为假,说明后面99条全为假。可既然后面99条全为假了,那说明这个列表有99条为假,但是p1说只有1个为假,条件和结论相矛盾。所以假设不成立,说明p1为假。
同样的方法推断p2。假设p2为真,根据p2内容,后面的98条全是假的了,再算上p1已经为假了,说明列表里有99条为假,与p2内容矛盾。所以假设不成立,说明p2也为假。
同样推断出p3到p98也都是假的。
再看p99,假设p99为真,首先前面98条已经证明为假的了,再根据p99的内容”恰有99条为假“,还差1条,说明p100肯定为假。而从p100的内容”恰有100条语句“来判断,p100也确实为假(因为p99为真的,所以p100的内容是不对的)。这个由条件到结果是不矛盾的。保险起见,再假设p99为假的,因为前面98个已经证明为假了,而p99也假设为假了,现在共有99条假的了,再根据p99的内容,说明p100也必须为假,因为如果p100为真的话,那p99就是真话了。如果p100也为假的话,那说明这个列表全部都为假了,可是这样又到底了p100的内容是真的,条件到结论矛盾。再次证明了p99为真
再看p100,现在已知98都为假,p99为真,p99既然为真,那他的内容就是一个事实”恰有99条为假“,还差1条,只能说明p100为假了,如果p100为假的话,那么p100所陈述的内容就是假的,而事实也确实说明p100的内容为假。
所以最后的结果是:除了p99,其余全为假。
b)这个要反过来推到
先假设p100为真,那p100的内容就是真的”至少有100条假“,因为总共就100条,说明全都为假,可既然100条都是假,那p100也是假的,又矛盾了。表明p100应该为假的。(也可以从另外一个角度证明,p100的内容”至少有100条假“是真的,说明”至少有99条、98条、1条为假“都是真的,前面99条都为真的,那怎么还能至少100条为假呢,矛盾。表明p100为假)
同样方法推断p99,假设p99为真,由p99的内容推断p1到p98都为真,而p1到p98都为真显然是与p99的内容不符合的,矛盾。表明p99为假。
同样推断出p98到p51都为假的。
再看p50,假设p50为真,由p50的内容推断p1到p49也都为真,说明50条为假的语句只能是p51到p100了,而事实上p51到p100也确实都为假,不矛盾。表明p50应该为真。保险期间,我们再假设p50为假,那说明p50的内容”至少50条语句为假“是不对的,可是p51到p100这50条语句已经证明为假了,矛盾。再次表明p50应该为真。
接着看p49,假设p49为真,由p49的内容推断p1到p48都为真,而p51到p100都为假,也论证了p49的内容是没错的,没有矛盾。p49为真
同理推断出p48到p1也都为真。
所以最后的结果是:p1到p50为真,其余为假。
c)同样方法推断出p99到p51为假
推断p50,假设p50为真,由其内容推断出p1到p49都为真,一共99条语句,p1到p49为真,p50也假设为真了,只剩下49条语句根本凑不成50条为假了,所以矛盾,p50为假。可是p50如果为假的,由于p51到p99这49条已经为假了,再加上p50又为假,说明这个列表确实至少有50个为假,这样说明p50的内容是对的,p50应该是真的,再次矛盾。可见无论p50为真还是为假,都矛盾。说明这是个悖论。

posted @ 2012-09-26 15:31 古月 阅读(1443) | 评论 (0)编辑 收藏

2012年9月19日

c++中explict关键字的说明和使用

先看下面这一个简单的代码吧

 1 #include <iostream>
 2 using namespace std;
 3 class my
 4 {
 5 private:
 6     int t;
 7 public:
 8     my(){};
 9     my(int i):t(i){};
10     int get()
11     {
12         return t;
13     }
14     void print(my d)
15     {
16         cout<<d.get()<<endl;
17     }
18 };
19 
20 int main()
21 {
22     my t;
23     int i=3;
24     t.print(i);
25     return 0;
26 }

main函数中t.print(i);的调用,my类里面print函数接受的数据类型的my,不是int,但这段程序仍然能够正常运行,是因为my类里面存在一个只有一个形参的构造函数。

当在一个需要my类型对象的地方(比如print函数,就需要一个my类型对象),但是如果却没有给一个my类型对象,给了一个其他类型的对象,比如int,那么这个时候就会看这个类有没有定义一个只接受一个参数的构造函数,而且这个形参必须是int,然后构造出一个my类型临时对象,再把这个临时对象给需要my类对象的地方,完成一种隐式的转换。
注意:如果这个类有一个接受一个参数的构造函数,但是这个参数的类型比如是string,这个隐式转换肯定就不会发生了,编译时会提示错误。

总之,隐式转换会发生在,本来需要一个这种类对象的时候,却给了一个其他的数据类型,而且类也恰好有一个只接受一个这种数据类型参数的构造函数,就会先调用这个构造函数生成一个临时对象,接着将这临时对象用于需要这种类对象的地方。

但是很多时候,这种隐式转换会带来很大的麻烦,因此如果自己定义的类中,有一个只接受一个参数的构造函数,除非有一个好理由允许构造函数被用于隐式类型转换,否则那么就要在这个构造函数前面加一个关键词 explicit,表明不会发生隐式转换。

posted @ 2012-09-19 18:15 古月 阅读(577) | 评论 (0)编辑 收藏

2012年6月7日

再谈下声明、定义、初始化、赋值和extern

虽然定义也是声明,但为了方便说明问题,下文中的声明只是单纯的声明,定义就只是定义。

1.      声明、定义、初始化和赋值四个术语有着本质的不同,虽然有时候看起来差不多甚至完全一样,但如果不搞清楚很容易出现错误,或者错了不知道怎么改。

 

2.     a: extern关键词用来表明这是一个声明:extern int I;变量i就是一个声明。声明前面一定要有一个关键字extern,没有这个关键词就不是一个声明。

b: 没有extern就是一个定义,比如int i=9;是一个定义,特别要注意的是int i;这也是一个定义。

c: 初始化就是在变量定义时给变量一个初值,所以初始化语句也一定是一个定义语句,但反过来就不对了,因为类似于:int i;就是定义,但没有初始化。特别要注意的是:extern int i = 9;虽然有extern关键词,但是因为初始化了,所以这也是一个定义,不是声明。

d: 赋值语句就简单了,赋值语句是给一个已经定义的变量(不管这个变量有没有初始化)一个新值。特别要注意的是,要给赋值的变量必须已经定义过了,仅仅声明是不行的。

 

3.       extern关键词除了表明这是一个声明以外,更重要的是表明:所声明的变量的定义可能是在程序中其他文件里。如下代码

    //file1.cpp

#include <iostream>
using namespace std;
extern int i;//这是一个声明,告诉编译器变量i的定义有可能是在其他源文件中,即使本文件中没有i的定义,你也不要报错。
void main()
{
    extern int i;//同样是对i的声明,作用与上面的声明完全一样,说明声明可以存在多个,实际上这两个声明只要任意一个就可以了。但是两个声明语句如果一个都没有,编译器就会认为变量i没有定义,会报错。

    i=0;//赋值语句,给变量i一个新值,变量赋值前必须要已经定义了,如果不存在file2文件中的定义语句,虽然不会出现编译错误,但是链接会有错。
    cout<<i;
}

//file2.cpp

int i;//首先是一个定义,而且是一个没有初始化的定义(不过实际上全局变量i被默认初始化为0),变量i被定义在file2源文件中

 

 

4.      一个程序中可能包括不只一个文件,所有文件中同一个变量(其实主要说的全局变量)必须总共只能定义一次,但是声明可以有无数个。而且如果文件A中用到的变量的定义是在其他文件中,那么在文件A中用这个变量之前,一定要加上一句extern声明语句,告诉编译器我所用的这个变量有可能是在其他文件里

5.   extern int i=9;上面已经提到虽然有extern,但这也是一个定义,因为初始化了。类似于这种有extern也有初始化的语句,只能出现在全局作用域,如果出现在函数内部,这是错误的。

6.       (转)有关编译器的一个特点:现代编译器一般都属于按文件编译,就是说编译时多个源文件自己编译自己的,互不影响,好像只有自己一个文件。只要每个文件编译时没有出现错误,那么就不会发生编译时错误。但是没有发生编译错误,并不代表程序就没有错误,因为还会发生链接错误。比如下面这两个代码

     //A.cpp
int i;//这是变量i的定义
 
void main()
{
}

//B.cpp
int i;//这也是变量i的定义
编译时两个文件A和B是相互不影响的,所以编译时不会出现任何错误,但是这个程序是有问题的,因为全局变量i是被定义了两次的,所以链接时就会报告类似于下面的错误:

B.obj : error LNK2005: "int i" (?i@@3HA) already defined in A.obj

Debug/A.exe : fatal error LNK1169: one or more multiply defined symbols found

另外上面也提到了,编译时各个文件是相互不影响的,编译器是不会认为在这个文件中没有定义的变量其实很有可能人家是个全局变量,在其他文件中定义了,这就要报错。解决方法就是用extern声明一个变量,告诉编译器人家这个变量不是没有定义,只是在其他文件中定义了,你别报错了。

 

posted @ 2012-06-07 15:41 古月 阅读(3673) | 评论 (0)编辑 收藏

2012年5月28日

新学到的有关cin输入流的特点、用法

#include <iostream>

using namespace std;
void main()
{
    double val;
    char ch0,ch1;
    cin>>val;
    cout<<val<<endl;
    cin>>ch0;
    cout<<ch0<<endl;
    cin>>ch1;
    cout<<ch1<<endl;
}

cin输入流用法之前学的不认真,忽略到了。
这段代码很简单,开始第一个输入的时候,比如直接输入:123ab。最后的结果是把123给了val,a给了ch0,b给了ch1。
也就是说,当cin给一个double时,这时如果你的输入是123ab,不是单纯的一个数字时,那么将只是把输入的数字部分123给double,但是剩下的ab不是简单的遗弃掉,而是继续留在输入流中,等待下一次出现cin再把ab给到下一个要从输入流得到值的变量。

posted @ 2012-05-28 00:20 古月 阅读(606) | 评论 (0)编辑 收藏

2012年1月13日

鄙人这辈子编写的第一个游戏程序:猜拳! 好激动,共享下c++源代码

     摘要: 石头剪子布的猜拳游戏,在VC下编译运行下,生成的.EXE文件,就可以单独拿出来玩游戏了。这个游戏属于1.1版本,最原始的1.0版本主要部分和这个差不多,1.1主要是在原来的基础上与玩家的交互做了一些更加友好的改进(感谢提出改进意见的宿舍兄弟)程序基本没有太大的技术含量,自认为程序核心的部分:电脑随机给出的猜拳。本人想到了一个很简单但自认为挺巧妙的方法(小小的骄傲下),不多说了看代码吧,如果代码有什...  阅读全文

posted @ 2012-01-13 22:30 古月 阅读(3861) | 评论 (7)编辑 收藏

2011年12月25日

字符串操作函数中的参数问题

这个首先先解释下一个很基础但是却很重要又常常容易搞混的问题。
char a[]和char*的区别。
《c语言程序设计》(中文版)的解释挺不错的,我再大概说一下。
..............................
char ame[] = "nw is the time";
char *pme = "now is the time";
首先说pme是把一个指向该字符数组的指针赋值给pme.这个过程没有涉及到字符串的复制,只是有指针的操作。pme首先是一个指针,这个指针指向一个字符串常量,这个指针此后可以被修改为指向其它字符串,但是如果修改字符串本身的内容,结果是未定义的。ame是一个存放初始化字符串和空字符的一维数组,数组中的单个字符都是可以被修改的,但是ame是个地址常量,是不可以被修改的,它始终指向这一个字符串。

string.h中定义了很多字符串操作函数,比如strncat,这些函数至少都有两个参数,第一个参数是目的字符串,第二个参数是源字符串。
关于这个参数的类型到底用哪种,要看相关的参数内容在函数执行完以后是不是会发生改变。如果参数内容发生改变了就要用char[],如果参数的内容不发生改变则两个都可以用。

比如strncat(s,ct,n),函数的作用是把ct的前n个字符连接到s的后面,最后补上一个空字符。那么显然执行完以后s的内容是变化了的,所以定义s是必须是char s[80],不能是char *s,对于ct来说内容没有发生变化,怎么定义就都可以了。

posted @ 2011-12-25 16:25 古月 阅读(707) | 评论 (0)编辑 收藏

仅列出标题  下一页
<2011年6月>
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789

导航

统计

常用链接

留言簿

随笔分类

随笔档案

文章档案

C++/C

搜索

积分与排名

最新评论

阅读排行榜

评论排行榜