c++ 学习

类别:编程语言 点击:0 评论:0 推荐:

一.获取时间   请问如何计算一个程序运行的时间? 用什么函数来获得当前时间?
1.用difftime,秒级

#include <time.h>
#include <stdio.h>
#include <dos.h>

int main(void)
{
   time_t first, second;

   first = time(NULL);  /* Gets system   time */

  // 你的程序    ...............


   second = time(NULL); /* Gets system time    again */

   printf("The difference is: %f seconds\n",difftime(second,first));
   getch();

   return 0;
}

2.用DWORD GetTickCount(VOID)
CTime WINAPI GetCurrentTime( ) throw( );
获得更精确的时间 GetTickCount

3.获取系统编译程序的时间
char* time1 = __DATE__;
char* time2 = __TIME__;
其中__DATE__和__TIME__是俩个宏。

二,IO算子

cout<<"Hello world!"<<flush<<endl; ---强制输出
   cout<<endl;
   cout<<ends;          -----输出一个null字符
   cout<<setfill('*');   -----和setw配合使用,将空白区用指定字符输出
   cout<<setw(14)<<"how"<<setw(14)<<"how"<<endl;--set width
   double d = 33.11444;
   cout<<setprecision(4)<<d<<endl;----设置小数点的位数
   cout<<dec<<10<<endl;----一旦设定,后面的全部跟随。
  
   cout<<hex<<10<<endl;
   cout<<oct<<10<<endl;
   setbase(n);----更改原来设置的进制。如更改为16进制,setbase(16);
   int a;
   cin>>hex>>a;   ----以hex输入
   cout<<dec<<a<<endl;
  
  
三、内存对齐问题(关键字,内存对齐)
typedef struct
{
 int a[10];
 char ch[10];
 int f[10];
 bool b[10];
}MType;


int _tmain(int argc, _TCHAR* argv[])
{

 int i;
    MType mt; 
 
 printf("%d",sizeof(MType));
 getch();
 return 0;
}
这个结构中,本来按我们计算sizeof(MType)是100,然而结果是104。在vc和
linux下的dev c++都是。
原因是内存对齐问题。一般编译器认为内存以4的倍数对齐。仔细分析内存可以得出
结论,不够4,要向后移动,凑成4的倍数。这个机构的一个对象就涉及了向后移动2
字节,补全2字节。故为104。

可以在文件最前面加#pragma pack(1) 这是将编译器该成为1的倍数对齐,这样求出的
长度就为100了。

四。分位定义
typedef unsigned char _uint_8;
typedef struct
{
 _uint_8 hi4:2,
            lo4:6;
}MyByte;
表示将一个字节分成俩部分,前面2位,后面6位。
使用:

 MyByte b;
 b.hi4 =  10;
 b.lo4 = 2;

 cout<<b.hi4<<endl;
 cout<<b.lo4<<endl;
注意:不能夸字节定义。必须定义在结构里方可使用。

五,关于new


new"分配"的内存当然都在堆中。
但new并不仅仅只有分配内存的作用,它还可以在已有内存(包括栈内存)上强制重新构造对象的作用。

如:
#include <iostream>
using namespace std;

class A
{
public:
 int i;
 int j;
 A(int _i , int _j) { i = _i; j = _j; }
};

int main()
{
 A a(3, 4);
 cout << a.i << a.j << endl;
 new (&a) A(5,6);
 cout << a.i << a.j << endl;

 return 0;
}

六、关于n个随机数的和的问题
求m个随机数之和为n的算法。

void myRan(int n,int m)
{
 int i;
 int sum=0;
 int *a = new int[m];
 for (i=0; i<m; i++)
 {
  a[i] = 0;
 }
 for(i=0; i<m-1; i++)
 {
  a[i]=rand()%(n + 1-sum);
  sum+=a[i];
  cout<<a[i]<<'\t';
 }
 a[m-1]=n - sum;
 cout<<a[m-1]<<endl;
 delete []a;

}
七,关于结构的定义和赋值
typedef struct
{
   int a;
   short b[2];                  /*定义第一个结构体*/                     
}Ex2;
typedef struct Ex1
{
    int a;
    char b[3];
    Ex2 c;                     /*定义第二个结构体*/ 
 Ex1 * d;
}Ex1;
我们看第二个结构,Ex1 必须写在括号的前面,否这编译不会通过,大概是不识别
结构种的Ex1符号吧。而后一个Ex1可以写,也可以不写。
如果结构种没有自身的指针,那么,机构的名字可以放在结构定义的末尾,
也可以是结构体的开始。 另外,结构体种不能用结构自身定义成员,可以用结构
的指针定义成员例如:
typedef struct Ex1
{
    int a;
    char b[3];
    Ex2 c;                     /*定义第二个结构体*/ 
 Ex1 d;  //错误,可以用结构的指针,但是不能用结构自身定义对象。
}Ex1;

结构体的赋值:
对于上面的俩个结构:
typedef struct
{
   int a;
   short b[2];                  /*定义第一个结构体*/                     
}Ex2;
typedef struct Ex1
{
    int a;
    char b[3];
    Ex2 c;                     /*定义第二个结构体*/ 
 Ex1 * d;
}Ex1;
上面是c语言的定义方式,在C++中,可以省略掉typedef,比如:
struct Ex1
{
    int a;
    char b[3];
    Ex2 c;                     /*定义第二个结构体*/ 
 Ex1 * d;
};
这时,c++编译器可以识别出Ex1,并且可以直接用Ex1定义对象,不用再加strcut。
比如:Ex1 e1;

所以关键看是什么编译器,我用g++ 编译后者没有错误。用gcc就出现了好多错误。
可见后面的是c++支持的。在c++编程思想上有说明。Ch2,P12
可以这样赋值。
 Ex2 e2 = {10,{10,10}};
 Ex1 e1={10,"Hi",{5,{25,25}},0};
 
八,关于内存问题:
从总体上程序的内存空间可分为代码区和数据区。
从C++的角度来看数据区又可作如下划分:
1. 自动存储区(栈):自动(局部)变量、寄存器变量(声明的寄存器变量可能在寄存器中,也可能在一般内存中。在逻辑上寄存器属于自动存储区。)、临时对象以及函数参数。
2. 静态存储区:全局对象、函数中的静态变量、类中的静态数据成员、常量字符串以及 namespace 变量(比如 namespace abc = std;中的 abc。)
3. 自由存储区(堆):也称为动态内存。

一个可执行文件、.o、.a文件中系统规定的段有这么多
* .bss
该sectiopn保存着未初始化的数据,这些数据存在于程序内存映象中。通过定义,当程序开始运行,系统初始化那些数据为0。该section不占文件空间,正如它的section类型SHT_NOBITS指示的一样。
* .comment
该section保存着版本控制信息。
* .data and .data1
这些sections保存着初始化了的数据,那些数据存在于程序内存映象中。
* .debug
该section保存着为标号调试的信息。该内容是未指明的。
* .dynamic
该section保存着动态连接的信息。该section的属性将包括SHF_ALLOC位。是否需要SHF_WRITE是跟处理器有关。第二部分有更详细的信息。
* .dynstr
该section保存着动态连接时需要的字符串,一般情况下,名字字符串关联着符号表的入口。第二部分有更详细的信息。
* .dynsym
该section保存着动态符号表,如“Symbol Table”的描述。第二部分有更
详细的信息。
* .fini
该section保存着可执行指令,它构成了进程的终止代码。
因此,当一个程序正常退出时,系统安排执行这个section的中的代码。
* .got
该section保存着全局的偏移量表。看第一部分的“Special Sections”和第二部分的“Global Offset Table”获得更多的信息。
* .hash
该section保存着一个标号的哈希表。看第二部分的“Hash Table”获得更多的信息。
* .init
该section保存着可执行指令,它构成了进程的初始化代码。
因此,当一个程序开始运行时,在main函数被调用之前(c语言称为main),系统安排执行这个section的中的代码。
* .interp
该section保存了程序的解释程序(interpreter)的路径。假如在这个section中有一个可装载的段,那么该section的属性的SHF_ALLOC位将被设置;否则,该位不会被设置。看第二部分获得更多的信息。
* .line
该section包含编辑字符的行数信息,它描述源程序与机器代码之间的对于关系。该section内容不明确的。
* .note
该section保存一些信息,使用“Note Section”(在第二部分)中提到的格式。
* .plt
该section保存着过程连接表(Procedure Linkage Table)。看第一部分的``Special Sections''和第二部分的“Procedure Linkage Table”。
* .rel<name> and .rela<name>
这些section保存着重定位的信息,看下面的``Relocation''描述。
假如文件包含了一个可装载的段,并且这个段是重定位的,那么该section的 属性将设此,一个重定位的section适用的是.text,那么该名字就为.rel.text或者是.rela.text。
* .rodata and .rodata1
这些section保存着只读数据,在进程映象中构造不可写的段。看第二部分的`Program Header''获得更多的资料。
* .shstrtab
该section保存着section名称。
* .strtab
该section保存着字符串,一般地,描述名字的字符串和一个标号的入口相关 联。假如文件有一个可装载的段,并且该段包括了符号字符串表,那么section的SHF_ALLOC属性将被设置;否则不设置。
* .symtab
该section保存着一个符号表,正如在这个section里``Symbol Table''的描述。假如文件有一个可装载的段,并且该段包含了符号表,那么section的SHF_ALLOC属性将被设置;否则不设置。
* .text
该section保存着程序的``text''或者说是可执行指令。

前缀是点(.)的section名是系统保留的,尽管应用程序可以用那些保留的section名。应用程序可以使用不带前缀的名字以避免和系统的 sections冲突。object文件格式可以让一个定义的section部分不出现在上面的列表中。一个object文件可以有多个同样名字的 section。
引用:
简单地说有如下结构
命令行参数和环境变量


未初始化数据段bss
初始数据段
正文段


C程序一直由下列部分组成:

1)正文段——CPU执行的机器指令部分;一个程序只有一个副本;只读,防止程序由于意外事故而修改自身指令;
2)初始化数据段(数据段)——在程序中所有赋了初值的全局变量,存放在这里。
3)非初始化数据段(bss段)——在程序中没有初始化的全局变量;内核将此段初始化为0。
4)栈——增长方向:自顶向下增长;自动变量以及每次函数调用时所需要保存的信息(返回地址;环境信息)。
5)堆——动态存储分。

|-----------|
| |
|-----------|
| 栈 |
|-----------|
| | |
| \|/ |
| |
| |
| /|\ |
| | |
|-----------|
| 堆 |
|-----------|
| 未初始化 |
|-----------|
| 初始化 |
|-----------|
| 正文段 |
|-----------|


http://community.csdn.net/Expert/topic/3215/3215569.xml?temp=.3182337

       low address
   +--------------------------------+
   |   _TEXT class 'CODP'           |
   |        code                    |
   +--------------------------------+--
   |   _DATA class 'DATA'           |
   |     initialized data           |
   +--------------------------------+ DGROUP
   |   _BSS class 'BSS'             |
   |     uninitialized data         |
   +--------------------------------+--
   |                                |
   |     FREE SPACE                 |
   +--------------------------------+
   |                                |
   |     STACK                      |
   +--------------------------------+
   |                                |
   |     HEAP                       |
   +--------------------------------+
   |                                |
   |     FREE SPACE                 |
   +--------------------------------+
         high address

九、怎么快速检测出一个巨大的链表中的死链?我实在没有想出好办法,
只能说,没办法,只能一个一个的比了...各位高手有没有什么好办法?
死链:链表的某个接点的next指针指向了曾经出现过的接点,导致链表死循环。
刚才忘了说:该链表是单链。

老迈的解决办法,很牛:
以前的帖子里有这道题的简化版的答案,我再贴一次吧,呵呵。
如果只是判断链表中是否有回路而不用具体求出回路的具体路径的话,则有一个取巧的办法。
开两个遍历链表的指针,一个一次往前走一个结点,另一个往前走两个结点,
当这两个指针相遇时,如果该接点的next==null,则无回路,否则说明有死链。

十,关于句柄类的信息,看c++编程思想Ch3,p12。

一,
为分削得人憔悴,
跺上高楼,
跺上高楼,
原来众人都在楼上。

二,关于数组的赋值:
struct Node
{
 int n;
 float f;
 char ch;
};
int main()
{
 int str[20] = {1,50,3};//剩余元素都为0。只要有个,剩余都为0;
 //但是如果没有初始化,int str[20];这时,数组并不初始化为0。而是任意值
 Node nodeArr[20] = {{1,1.1,'a'}};//在没有构造函数的情况下,
 //和前目数组一样,剩余节点都初始化为0。
 //除第一个节点外,后面的个元素{0,0.0000,0}
 int i;
 for(i=0; i<20; i++)
 {
   printf("%d  ",str[i]);
   printf("%d  %f  %c\n",nodeArr[i].n, nodeArr[i].f, nodeArr[i].ch);
 }
 printf("\n");
 return 0;
}

但是在有了构造函数的情况下,用法就不同上面:
struct Node
{
 int n;
 float f;
 char ch;
 Node();
 
};
Node::Node()//默认构造函数
{
 n=1;
 f = 1.1;
 ch = 'b';
}
int main()
{
 //int str[20] = {1,50,3};
 //Node nodeArr[20] = {{1,1.1,'a'}};//这种用法编译错误,要求用构造函数构造对象
 Node nodeArr[20] = {};// 每个Node对象调用默认构造函数,内部成员分别为
         // 1,1.1, 'b'
 //可见:如果没有构造函数,就用与c相同的语法编译,
 //如果有了构造函数,就必须用构造函数进行数组的初始化。这里就构和类是一样的
 int i;
 for(i=0; i<20; i++)
 {
   //printf("%d  ",str[i]);
   printf("%d  %f  %c\n",nodeArr[i].n, nodeArr[i].f, nodeArr[i].ch);
 }
 printf("\n");
 return 0;
}

四,一个有趣的面试题:
哪为高手能帮帮我,
在不使用if,while,do~~while等语句,不使用关系运算符,不使用MAX(),MIN()
的情况下,怎样比较输入的a,b两个数的大小。(注:实现并不知道输入的数的大小)
float max(float a,float b)
{
   float t1,t2;
   t1 = a + b;
   t2 = sqrt((a-b)*(a-b));//免得你说fabs中也用了判断语句
   return (t1 + t2)/2;
}
这里藏着很好的道理。t1 是二者的和,t2是大着比小者大的部分。如果把大出的
部分加到小者的上面,正好是2倍的大者。

三,关于省缺参数的定义。
如果一个程序只有一个cpp文件,而且这个函数没有函数声名,只有函数定义,那么
这个函数的省缺参数可以放到函数定义中。比如:这种情况:
#include <iostream>
using namespace std;
void fun1(int m = 3, char ch = 'b')
{}
int main ()
{
 
   fun1(); 
   fun2();
   return 0;
}

如果一个程序,有头文件,在头文件中有函数声名,或者没有头文件,但是有函数声名
这种情况下,省缺参数必须放在函数的声名中,不能放在函数定义中,否则编译错误。
比如:
//links.h
void fun2(int m=3,char ch='a');


//links.cpp
#include <iostream>
#include "links.h"
using namespace std;
void fun1(int m = 3, char ch = 'b');//有声名,必须在声名处给出省缺参数
void fun2(int m/*=3*/,char ch/*='a'*/)//声名中给出,再不能在定义中设置省缺参数
{
}
void fun1(int m /*=3*/, char ch/* = 'b'*)//声名中给出,再不能在定义中设置省缺参数
{}
void fun3(int m=3, char ch='c')//没有函数声名,可以在定义时给出省缺参数
{}
int main ()
{
 
   fun1(); 
   fun2();
   fun3();
   return 0;
}

四,分布式系统
分布式系统是通过通信网络将物理上分布的具有自治功能的数据处理系统或计算机
系统互联起来,实现信息交换和资源共享,协作完成任务。分布式系统要求一个统
一的操作系统,实现系统操作的统一性。分布式操作系统管理分布式系统中的所有
资源,它负责全系统的资源分配和调度,任务划分,信息传输控制协调工作,并为
用户提供一个统一的界面,用户通过这一界面实现所需要的操作并使用系统资源,
至于操作定在哪一台计算机上执行或使用哪台计算机的资源则是操作系统完成的,
用户不必知道。此外,由于分布式系统更强调分布式计算和处理,因此对于多机合
作和系统重构,健壮性和容错能力有更高的要求,要求分布式操作系统有更短的相
应时间,更高吞吐量和更高可靠性。

五,冒泡排序算法:
void order(char* chs, const int& n)
{//冒泡排序算法,zhangggdlt
 int i,j;
 int maxSubscript;
 for (i=0; i<n; i++)//n-1
 {
  chs[0] = chs[1];
  maxSubscript = 1;
  for (j=2; j<=n-i; j++)
  {
   if (chs[0]<chs[j])
   {
    chs[0] = chs[j];
    maxSubscript = j;
   }
  }
  chs[maxSubscript] = chs[n-i];
  chs[n-i] = chs[0];
 }
 chs[0] = ' ';
}
六、关于命名空间
namespace A{
#define MIN 20
int k = 3;
}
其实,#define MIN 20 可以穿透命名空间,
也就是说不受命名空间限制,所以放入放出无所谓,建议放在外面。
构造函数不能是静态函数。

七:关于多字节数据类型在内存中的存储问题:
int ,short 分别是4、2字节。他们的存储方式是:
int data = 0xf4f3f2f1;
其中低位存放在编址小的内存单元,高位存放在编址搞的内存单元
地址:0x8000      0x8001    0x8002   0x8003
数据: f1           f2         f3      f4

八、枚举型定义,枚举元素的值可以重复。
typedef enum
{
 monday=1, cat,tuesday=1,dog
}week;
用法:
week w = dog;
int k = tuesday;
上面都是可以的。

此时,dog的值是它前面的值加一,里面有俩个元素值是相等的。同理,cat也一样。
cat 和 dog的值都是2。

九,获取时间,包括星期的程序
#include<time.h>
#include <stdio.h>


int main(){
char *wday[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
time_t timep;
struct tm *p;
time(&timep);
p=localtime(&timep); /*取得当地时间*/
printf ("%d.%d.%d ", (1900+p->tm_year),(1 +p->tm_mon), p->tm_mday);
//注意月份载localtime是从0。。11 代表1到12月,所以要加1。
printf("%s  %d:%d:%d\n", wday[p->tm_wday],p->tm_hour, p->tm_min, p->tm_sec);
return 0;
}

十、各个分析
#include <iostream>
using namespace std;

class A{
 int x;
};

class B:public A
{public:
    int b1;
 B(){b1=2;}
 int geti(){
  cout<<"geti called,b1 is "<<b1<<endl;
  return 1;
 }
};

int main()
{
 
 A a;
 B b;
 int k;
 B* pb=(B*)&a;
 pb = (B*)&k; 
 pb->geti(); 
 int i;
    cin>>i;
 return 0;


}

分析:
你的类A是基类,类B是子类。
把基类的对象a的地址,强制转换成子类的地址。这样很危险,会导致数据裁减。其实是更本不希望这样做的。强制类型转换,可以将任何类型都可以转换,虽然语法没有错误,但是语意上没有意义。比如:我们可以
int k;
B* pb=(B*)&k;
这样编译也没有错误,但是,更本没有意义。

你的转换同样也是一个道理。你的a对象里跟本就没有B类函数geti所要用的东西,但是对于计算机来说,它不管这些,它只要对指针所指的内存进行操作就行了,它认为从指针所指的位置开始,后面就是一个B类对象。所以编译可以通过。
但是没有意义。

一、数字加密算法DES(Data Encryption Standard)

本文地址:http://com.8s8s.com/it/it26906.htm