编程日志(C++)

这是我去年以及近来学习C++的一些笔记,里面有许多问题是不太合理的,有些是我现在已经搞清楚的,但还是以原来的版本贴在我的BLOG上,以后哪一天再来看的时候,也许会有别样的感觉:

2004.4.1

小弟初学C++,有些问题不太明白,
(1)有语句为a+=b;以及a=a+b,书上说前者比后者执行效率高,为什么?
(如果可以从a,b,+在内存中的存放地,调用,以及CPU具体如何执行该命令的角度说说最好^-^)


(他们的回答是不产生临时变量,好像是这样吧!)

 

(2)C++中当一个函数带有多个参数时,标准中未规定在函数调用时实参的求值顺序,并允许不同的编译系统根据对代码优化的需要自行规定对实参的求值顺序,那么像:

#include<iostream>

using namespace std;

int fun(int,int);

void main()

{
    int x=1,y=1;

    cout<<"result is:"<<fun(++x,x+y)<<endl;

}
int fun(int i,int j)

{
    return i+j;
}

岂不是产生二义性了,那么ANSI标准委员会咱不吱声呢?难道有特殊的意义?还望各位高手各抒己见。

 

 

(3)C++与C相比,一点小小的语法差异就是C++中允许在函数被说明或定义的时候给一个或多个参数

指定默认值,但又规定要从参数表的右端开始,即在指定了默认值的参数右端不允许出现没有指定默认值的参数。为什么要这样规定呢?有什么特殊的意义吗?

(从这点出发,对于上面第2一个问题就可以这样考虑:依据这条规定,编译器若从左到右计算参数表中各个表达式,如果参数式很多很繁,一一执行到最后却发现最右端一个参数没有默认值,然后报告编译错误,那岂不是很没效率,所以如果我是编译器制作者,就规定它从右到左执行,果然VC6.0中上面结果为4!)

2004.4.5

  今天翻到数组那一节时看到如下的语句:
    char array[5]="hello";为合法语句,
按理说,元素个数已经超出了数组定义的大小,应该引发编译报错,但书上说:“该代码不会引起编译错误,但由于改写了数组
空间以外的内存单元,所以是危险的。”那为个么不规定编译器报错呢?


  还有如:
  int  iarray[10];
        iarray[0]=1;
        iarray[1]=2;
        iarray[2]=3;
        iarray[10]=11;
的语句,当程序执行到“iarray[10]=11;”的语句时,将会改变不属于数组空间的内存单元。书上又说:“这个代码的失误不会在程序
的编译与连接中反映出来,而是可能一直运行下去,直到出现结果不正确,或严重时导致死机。”既然如此,为会么不在编译时
检查报错呢?
  以为编译时必须确定数组的大小是为了精确的向操作系统申请内存空间可钱能说是“通常,声明数组方括号内的数字决定了数组的
大小。有初始化的数组定义又省略方括号中的数组大小时,编译器统计花括号之间的元素个数,以求出数组的大小”“让编译器得
出初始化的大小有几个好处。它常常用于初始化一个元素个数在初始化中确定的数组。提供程序员修改元素个数的机会!"
    
    ZTMCD!

2004.4.10

   今天学指针,比以前更明白了指针的定义及指向数组,指向函数,甚至指向文件的指针,书上有这么一段话:“给指针赋值
,要求指向的变量的类型相同,并且级别一致。”类型相同尚可理解,级别一致的解释是:“一级指针只能接受一般变量和数组
元素的地址值而不能接受一个二维数组的数组名,因为二维数组的数组名相当于二级指针。”
   不可思议的是,旁边就有这样的例子:
     int b[2][3],(*p)[3];
       p=b;
这句下边的解释是:“一个二维数组可以看成是由若干行组成的数组,每一行相当于一个一维数组,这个一维数组由若干个元素组成。b[2][3]就是一个二行三列的数组。p指向该数组的弟0行,这一行是由3个元素组成的一维数组。”
   这不是CD吗?
这段实际正确,是这样的!
   


   还有一个将指定字符串逆输出的例子比较好:
#include<iostream.h>

int strlen1(char a[ ]);
void main()
{
   char s[ ]="abcdefg";
   char * p;
   int n=strlen1(s);
   for(p=s+n-1;p+1!=s;p--)
   {
       cout<<*p;
    }
   cout<<endl;
}


int strlen1(char a[ ])
{
   char*p=a;
   int i=0;
   while(a[i++]!='/0')
   {
     p++;
    }
   return p-a;
}
 
2004.4.24

  这几天又是学C++啊,学到结构那一部分,只是觉得是类的一个前期准备,不过老太婆已经讲到类快结束的地方了,我却还在结构链表那个地方,不过这个地方还挺有意思的,正好解决了前几天想的无限制存放的功能,爽啊!
今天还学到了[conio.h]头文件中的一个函数[_getch()],  [ int _getch(void)];可以从键盘读取一个字符,但不回显,被我成功的运用到了book.exe中了,相似的一个函数是[getchar()],它是从键盘读取一个字符,但要回显,它是包含在[stdio.h]中的,在[conio.h]中还有一个[getche()]函数,不同的是它要回显。在[stdio.h]中还有一个[gets()]函数,它从标准输入设备上读取一行字符,  [ char * gets(char * buffer)],例如:
char ca_line[255];
cout<<"Please input:"<<endl;
gets(ca_line);
cout<<ca_line<<endl;


2004.4.27

今天我去看C++提高篇时,发现了一个常量折叠的概念,有下面的例子:
#include<iostream.h>
const int a=3;
const int b=a+1;
float * f=(float*)&b;
char c[b+3];
void main()
{
  const char gc=cin.get();
 
  const char c2=gc+3;

  cout<<int(gc)<<c2;
}
下面的一句话说:
常量折叠:在可能的情况下,符号常量的值会代替名字的出现的过程。
但还是不知道这JB倒底是什么东西!

2004.4.28

不知怎的,这几天陷入了一种浑浑噩噩的状态,
好像生活把我迷失了一样,唉,倒底是生活迷失了我,还是我迷失了生活,没有人能告诉我,
我一天不知道怎么就好像过去了,连一件有意义的事都没有做,唉,难道这就是生活?
不行,我得找到原因,
应该是最近的生活太没规律了吧,作息太杂乱,加之呆在电脑前的时间太多了,这样下去可不行啊,我一定得变一变了:
首先每天要按规律作息,
其次要安排好近阶段的任务,也就是说截止到五一假满,
好了,打起精神,为明天的清醒而清醒吧!
任务:
(1):C++一直看到多重继承那儿;//直到今天还没到呢(9.25)
(2): 把下列程序完成:
 1                       ;
2:   74 页 4.7(?);
3                       ;
4:   ;
5:   ;
6:   231 页10.5,10.6;
7:   311 页13.2.

好了就这些了,还有就是要把选定的那几本杂志看完!


2004.4.29

今天看类的用法,毕竟类涉及到了抽象,看上去还真有点不好懂,不过这么一点小问题是难不了我的,另外今天在网上加入了一个学习群,可不能输给他们啊!要加油啊!
书上讲到类的成员函数时说:在类体内声明的且定义的成员函数视为内联函数,而在类体外定义的成员函数要内联则要加inline来声明。
那么类体内的成员函数要是有了复杂语句如switch,for等时编译器还会不会视为内联呢?
(有没有什么方法可以检测哪个函数是不是内联函数呢?查编译后的代码可以吗?)
还有发现普通内联函数在调用前要么用inline定义或声明,声明时一定要加inline,有了声明定义时不加inline也会被自动视为内联,但声明是没加到定义时加虽然可以通过编译,但编译器并不把它视为内联。

2004.5.15

      今天上网在组里有一个人问,如何知道一个指针变量的大小,我赶忙一搜,结果得知可以用sizeof( );其实我也不知道指针变量的大小,回来赶忙实验一下,发现不管何种类型的指针,内存中都占4个字节,如下:
#include<iostream.h>
void main()
{
  char c_a='a';
  char * pc_a=&c_a;
  cout<<sizeof(c_a)<<endl;
  cout<<sizeof(pc_a)<<endl;
  int i_a=255;
  int * pi_a=&i_a;
  cout<<sizeof(i_a)<<endl;
  cout<<sizeof(pi_a)<<endl;
  char ca_a[10];
  char * pca_a=ca_a;
  cout<<sizeof(ca_a)<<endl;
  cout<<sizeof(pca_a)<<endl;
}
其实可以想象到因为指针中放的就是地址,而地址是整型变量,就是4个字节啊!
[后记]:以前以为指针都是4个字节,可前几天上数据结构课时,吴小平提到链表的时候说一个指针是占8个字节的,说是段地址占4个字节,偏移地址占4个字节,一共是8个,好像也对,那以前拿sizeof( )函数求出的怎么是4个字节呢?估计那时编的是16位的控制台程序,就是4个字节吧。不行,得问问吴小平。
[2005.9.29]


2005.5.17

今天看到这么一个函数,rand( ),是包含于math.h头文件中的,[补记:今天查到rand( )不是包含在math.h 中的,而是在stdlib.h中的.]但如下代码不能通过编译:
#include<iostream.h>
#include<math.h>
void main()
{
 int a=rand();
 cout<<a<<endl;
}//改为stdlib.h后顺利通过。!!!
我本来想看看它们这个产生伪随机数的算法是什么,于是在DEBUG中打开.exe,结果只有这么些指令:

》[2005.9.29]
不知是何缘故,还有不知道如何表示一个数的多少次方,如2^3是不行的,但一定有库函数的,不过暂时没找到!
今天终于终于查到了,是在math.h中,
Pow( );
兼容性:ANSI, WINDOWS95, WINDOWS NT,
函数原型:
double pow(double x,double y);
说明:为计算x 的y次方!返回值即为结果
范例:
#include<math.h>
#include<stdlio.h>
void main(void)
{
     double x ,y;
     x=2;
     y=3;
     printf( “pow (%f, %f )=% f / n”,x, y,pow( x, y));
}


2005.8.6

这么多天以来,我每天都守着电脑,也许有的人注定一辈子都要与孤独,也许真的要守着这块代码的阵地来寻找那真正的理想,那么我会坚持下去,因为我相信宿命这个概念,也许有一天我会撑不下去,但我不管,在一步步融入电路的世界的时刻,我能体验到那种发自内心的快感,也许那就是我生命的源,尽管这样要失去一些东西,但我明白我已经没有归路,前面的路的确有一点黑暗,但我选择一个人走,说白了,这都不是为了什么,一切都只是过程而已,这条路,我会好好的走下去的

2005.8.19

理论上说,SWITCH()语句中的表达式要是整形或可以求出,那么以下的实验语句
............
char c_a='a';
switch(c_a)
{
    case 97 : cout<<c_a<<endl;
    //case 'a': cout<<"96 is not avoible!"<<endl;这儿会有编译错误,说是'a'已经存在,
}
运行结果是输出了'a',由此可见,c_a 与 97 必定有一个进行了类型转换,那么是c_a 的'a'转换成了97呢还是97 转换成了'a'呢?

97是字符a 的ASCII码值

 

2005.8.20

今天又一次学到UNION,书上有示例程序如下:

union Test
{
   char c;
   int i;
   float f;
};

int main()
{
   Test t;
   t.f=2.222;
   cout<<"t.i="<<t.i<<endl;
}


书上说会输出无用的信息,我想UNION中尽管只能存储一个数据,但把浮点数以整数输出也会是2吧,但实验结果大失我望,输出了什么1074672959,真是不明白!且看书上如何说:

UNION 把所有的数据放进一个单独的空间内,它计算出放在UNION 中的最大项所必需的空间数,并生成
UNION的大小,使用UNION 可以节省内存!
   每当UNION 中放置一个值,这个值总是放在UNION 开始的一个地方,但是只使用必需的空间。因此,我们创建的是一个能容纳任何一个UNION变量的“超变量” 。所有的UNION 变量的地址都是一样的(在CLASS或STRUCT 中,地址是不同的)。

但是当我把程序改为如下时:

union Test
{
   char c;
   int i;
   float f;
};

int main()
{
   Test t;
   t.f=2.222;
   t.c='a'
   cout<<"t.i="<<t.i<<endl;


这时程序输出了97,也就是字符a 的ASCII码值,真是不可思议,反正以后记着使用UNION时注意其副作用即可,其实现在的UNION 本来就已经是很少用的了!

 

 

2005.8.26

以前搞什么象学生成绩的保存啊什么的时候 ,大费周折的搞二维数组,现在学到了 string 型变量,想直接弄一个string 型数组,于是有了下面这些代码:


#include <iostream.h>
#include <string.h>


string str_array[5];


void main()
{
 cout<<"Please input 5 students' names:";
 for(int i=0;i<5;i++)
 {
  cin>>str_array[i];
 }
 for(int j=0;j<5;j++)
 {
  cout<<str_array[j]<<endl;
 }

}

结果编译错,我想是不是因为旧的C标准不支持string 型变量啊,于是换了前2行为:
 
#include <iostream>
#include <string>
using namespace std;


果然顺利通过,运行一切正常!


今天还做了一个变量以及函数代码在内存中的位置的验证实验,代码如下:
#include<iostream>

using namespace std;

char c_a='a';
int i_a=100;
float f_a=25.5;
double d_a=25.5;

void func(char,int,float, double);

void main()
{
 char c_b='b';
 int i_b=200;
 float f_b=25.5;
 double d_b=25.5;
 cout<<"&c_a:"<<(long)&c_a<<endl;
 cout<<"&i_a:"<<(long)&i_a<<endl;
 cout<<"&f_a:"<<(long)&f_a<<endl;
 cout<<"&d_a:"<<(long)&d_a<<endl;
 cout<<"/n&func():"<<(long)&func<<endl;
 cout<<"/n&c_b:"<<(long)&c_b<<endl;
 cout<<"&i_b:"<<(long)&i_b<<endl;
 cout<<"&f_b:"<<(long)&f_b<<endl;
 cout<<"&d_b:"<<(long)&d_b<<endl;
 func(c_a,i_a,f_a,d_a);
 func(c_b,i_b,f_b,d_b);
}

void func(char c_c,int i_c,float f_c,double d_c)
{
 cout<<"&c_c:"<<(long)&c_c<<endl;
 cout<<"&i_c:"<<(long)&i_c<<endl;
 cout<<"&f_c:"<<(long)&f_c<<endl;
 cout<<"&d_c:"<<(long)&d_c<<endl;
 cout<<endl<<endl<<endl<<endl;
}
得到结果为:
&c_a:4672960
&i_a:4672964
&f_a:4672968
&d_a:4672976

&func():4199005

&c_b:1245052
&i_b:1245048
&f_b:1245044
&d_b:1245036
&c_c:1244940
&i_c:1244944
&f_c:1244948
&d_c:1244952

&c_c:1244940
&i_c:1244944
&f_c:1244948
&d_c:1244952

Press any key to continue

 

2005.10.14

这么多天以来,一直没有学C++,不知道忙了些什么,就是基础学科的拉,但我明白C++是不可以放松的,以后可要靠这个混饭吃的呢,那个作业也没交,不过我一定搞一个超级完美的上去,大致想法如下:
1.0 普通实现学生成绩存储管理,要用到链表,用文件保存信息,每次读取即可。
2.0 用MFC实现GUI ,如果可以的话,内置数据库实现信息保存。
3.0 进一步完善GUI,实现位图界面,功能更加完善。
4.0 实现动画图形界面,并实现网络传递,即有服务端和客户端。
OK,就这样了吧,现在开始拉!

2005.11.29

上次记日志是11.14,算来也一个多月了,这一个多月来干了什么呢?先是编程没做什么,哦,跟着几个SB要在那儿做什么PHP,本来这做好了的话,确实是件好事,不知道是那帮SB有问题呢,还是我自己有问题,反正就是什么都没让我做,一个霸着一个大摊子一点也不让,根本就是不给别人一个学习的机会,另一个虽然让我做了东西,但又好长时间不理你,真是不明白,还要受那个狼狈气,唉,算了算了,不想也罢,所以最近也没有看C++,一点也没看,因为最近看那个<<深入理解计算机系统>>可是看到第三章就再也看不下去了,因为里面提到的像什么“模运算”啊,什么的看不明白,所以就也放下不看了,这几天在赶线数,还落两章呢,一定要抓紧时间呢,可是今天上午又没去上课,中午又打游戏打到3点钟,真是不知道该说自己什么,唉


2005.11.2

距上次写东西以来,时间已经过去1年之久。这一年来,几乎没怎么编过程序,所以对C++的认识仍然停留在1年前的理解上,仍然是结构化的设计,编写,没用过一个类,不知道封装,不知道继承,不知道多态,所以这几天写数据结构的作业时就感觉很吃力,这当然也是由于编程经验太浅薄的原因,可是我们要学的不是C,而是C++,因为C++更加与流行的编程思想贴近,也方便以后学习JAVA或者C#什么的,所以我得好好看看C++了,可是那本C++编程思想对于语法讲解的不是太好,它更注重OO的思想,可是我还需要一些基础语法的使用技巧啊,因为从实际出发,好多东西我还理解的不是太深入,所以这次打算从C++ Primer一书入手,另外对于程序的调试,编译我也不是太了解,所以还需要一本书来指导我如何正确的调试程序。


2005.11.13

今天看到TC++PL第6章,习题中有一道是这样的:写一个函数atoi(const char *),它以一个包含数字的C风格字符串为参数,返回与之对应的int值,例如,atoi(“123”)应该是123。修改atoi() ,使之能够 处理简单的十进制数之外,还能处理C++的八进制和十六进制记法形式。修改atoi()以处理C++的字符常量记法。
我的第一个版本如下:
#include<cmath>
double aatoi(const char * p)
{
 double result=0;    //
 int n=0;        //用以记录整数的位数
 int flag=0;       //标记有无小数部分
 int m=0;        //用以记录小数的位数

 while(*p)
 {
  if(*p!='.'&& flag!=1){
   n++;
   p++;
  }
  else if(*p=='.'&&flag!=1) {
   flag=1;
   p++;
  }
  else{
   m++;
   p++;
  }
 }
 p--;         //还原指针到末位数字
 while(flag==1&&*p!='.'){
  result+=(*p-48)*pow(10,-m);
  m--;
  p--;
 }         //算出小数部分值
 if(*p=='.') {
  p--;
 }
 for(int i=0;i<n;i++)
 {
  result+=(*p-48)*(pow(10,i));
  p--;
 }         //算出整数部分值+小数部分值
 return result;
}
在编的过程中发现atoi()原来是系统的一个标准函数,我一查函数词典发现在stdlib.h中有这么一系列函数:atof(),atoi(),atol(),
它们的函数原型分别是:
double atof(const char * string);
int atoi(const char * string);
long atol(const char * string);
说明如下:
每个函数通过转换输入字符串来产生double,int,long值,如果输入不能转换成对应类型的值,返回值为0(对于atoi()),0L(对atol()),或0.0(对于atof()).在溢出的情况下返回值是没有意义的。

(但是我遇到的情况是:不论字符串的长度是多长,用
cout<<aatoi(s_num)<<endl;
输出,结果只能保留7位有效数字,(包括小数点),比如如果字符串是:123.4567输出的结果是123.457,而123.4564的输出是123.456,显然是被4舍5入了,但double 的存储范围是15位啊,(因为sizeof(double)结果是8。而float的有效位数才是7,难道中间被什么转化了?然后我试了atof()也是同样情况,不明白!)

这些函数转换一个字符串为双精度浮点数,整数,和长整数,输入字符串是可以转换为指定类型的数值的字符序列,输出 的值受到当前环境中的LCNUMERIC设置的影响。有关LCNUMERIC的更多信息参见setlocale().(于是我查了该函数,它是位于locale.h中的一个标准库函数,用来定义一个本地化环境。
函数原型为:
char * setlocale(int category,const char * locale);
category :要规范的环境路径
locale : 环境的名称。
函数返回值:如果给定一个有效的本地化环境和目录,该函数返回与指定的本地化环境和目录关联的字符串的指针。如果该本地化环境和目录关联是无效的,该函数返回一个空指针且该程序不改变当前本地化环境设置。
总之简单来说我想大概就是可以通过该函数确保你的程序在另一个国家或地区在某些诸如时间显示格式等方面可以随地域的不同而自动适应。当做也包括上面提到的什么数型格式吧)
atof()所能处理的最大字符串长度是100个字符。当遇到第一个不能识别作为一个数值部分的字符时,该函数停止读输入的字符串。这个字符串可以是字符串结尾的空格字符(‘/0’)。
atof的string参数有如下格式:
[whitespace][sign][digits][.digits][{d|D|e|E}][sign][digits]
   这里whitespace由空格或制表符组成,它被忽略;sign是+或-,digits是一个或多个10进制数字。如果不数点之前没有数字,在小数点之后必须至少有一个数字。10进制数字可以紧跟一个指数,它由一个标志符d,D,e,E及可选的带符号的10进制数字组成。
atoi()和atol不能识别小数点或指数,这些函数的string由如下格式组成:
[whitespaces][sign][digits]


我的那个版本不能处理指数和符号,还不能处理8,16进制形式,真是不爽,然后我又看了由David Vandevoorde为TC++PL编得题解上的答案:

 

2005.11.24

下面是一个用来测试sizeof ( ) 的玩具程序,来处于The C++ Programming language 的练习册,代码如下:
#include<iostream>
#include<typeinfo>

template<typename T>
struct Type
{
 static void print()
 {
  std::cout<<"sizeof("<<typeid(T).name()<<")="
<<sizeof(T)<<std::endl;
 }
};

struct Polymorph
{
 virtual ~Polymorph()
 {
 }
};

enum Bit{zero,one};
enum Intensity{black=0,brightest=1000};


int main()
{
 wchar_t aaa='a';
 std::cout<<aaa<<'/n';
 Type<bool>::print();
 Type<char>::print();
 Type<signed char>::print();
 Type<unsigned char>::print();
 Type<wchar_t>::print();
 Type<signed short>::print();
 Type<unsigned short>::print();
 Type<signed int>::print();
 Type<unsigned int>::print();
 Type<signed long>::print();
 Type<unsigned long>::print();
#ifdef LONGLONG_ET
 Type<signed long long>::print();
#endif

 Type<float>::print();
 Type<double>::print();
 Type<long double>::print();

 Type<int *>::print();
 Type<int (*) ()>::print();
 Type<void (Polymorph::*) ()>::print();
 Type<void *>::print();
 Type<Bit>::print();
 Type<Intensity>::print();
 return 0;
}
所得结果是
 
也就是说VC++6.0中wchar_t是typeid或者typename不支持的,但是正常的使用还是可以的,另外还发现别的一些编译时的转化,比如指向函数或者成员函数的指针名就变为了内部名称了。有意思。另外,直接做sizeof(wchar_t)的结果是2。还有可以得出的是,VC++6.0中并没有long long 这种修饰的类存在。


 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值