Chinaunix首页 | 论坛 | 博客
  • 博客访问: 391326
  • 博文数量: 67
  • 博客积分: 1707
  • 博客等级: 上尉
  • 技术积分: 725
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-21 09:42
文章存档

2011年(5)

2010年(21)

2009年(41)

分类: C/C++

2009-10-28 14:44:22

·                                 1.是不是一个父类写了一个virtual 函数,如果子类覆盖它的函数不加virtual ,也能实现多态?

virtual修饰符会被隐形继承的。

private 也被集成,只事派生类没有访问权限而已

virtual可加可不加

子类的空间里有父类的所有变量(static除外)

同一个函数只存在一个实体(inline除外)

子类覆盖它的函数不加virtual ,也能实现多态。

在子类的空间里,有父类的私有变量。私有变量不能直接访问。


--------------------------------------------------------------------------
2.
输入一个字符串,将其逆序后输出。(使用C++,不建议用伪码)

#include
using namespace std;


void main()
{
  char a[50];memset(a,0,sizeof(a));
  int i=0,j;
  char t;
  cin.getline(a,50,'\n');
  for(i=0,j=strlen(a)-1;i  {
   t=a[i];
      a[i]=a[j];
   a[j]=t;
  }
  cout<}

//第二种

string str;
cin>>str;
str.replace;
cout<


--------------------------------------------------------------------------
3.
请简单描述Windows内存管理的方法。

内存管理是操作系统中的重要部分,两三句话恐怕谁也说不清楚吧~~
我先说个大概,希望能够抛砖引玉吧

当程序运行时需要从内存中读出这段程序的代码。代码的位置必须在物理内存中才能被运行,由于现在的操作系统中有非常多的程序运行着,内存中不能够完全放下,所以引出了虚拟内存的概念。把哪些不常用的程序片断就放入虚拟内存,当需要用到它的时候在load入主存(物理内存)中。这个就是内存管理所要做的事。内存管理还有另外一件事需要做:计算程序片段在主存中的物理位置,以便CPU调度。

内存管理有块式管理,页式管理,段式和段页式管理。现在常用段页式管理

块式管理:把主存分为一大块、一大块的,当所需的程序片断不在主存时就分配一块主存空间,把程序片断load入主存,就算所需的程序片度只有几个字节也只能把这一块分配给它。这样会造成很大的浪费,平均浪费了50%的内存空间,但时易于管理。

页式管理:把主存分为一页一页的,每一页的空间要比一块一块的空间小很多,显然这种方法的空间利用率要比块式管理高很多。

段式管理:把主存分为一段一段的,每一段的空间又要比一页一页的空间小很多,这种方法在空间利用率上又比页式管理高很多,但是也有另外一个缺点。一个程序片断可能会被分为几十段,这样很多时间就会被浪费在计算每一段的物理地址上(计算机最耗时间的大家都知道是I/O吧)。

段页式管理:结合了段式管理和页式管理的优点。把主存分为若干页,每一页又分为若干段。好处就很明显,不用我多说了吧。

各种内存管理都有它自己的方法来计算出程序片断在主存中的物理地址,其实都很相似。

这只是一个大概而已,不足以说明内存管理的皮毛。无论哪一本操作系统书上都有详细的讲解


--------------------------------------------------------------------------
4.
#include "stdafx.h"
#define SQR(X) X*X

int main(int argc, char* argv[])
{
 int a = 10;
 int k = 2;
 int m = 1;

 a /= SQR(k+m)/SQR(k+m);
 printf("%d\n",a);

 return 0;
}
这道题目的结果是什么啊?

define 只是定义而已,在编择时只是简单代换X*X而已,并不经过算术法则的

a /= (k+m)*(k+m)/(k+m)*(k+m);
=>a /= (k+m)*1*(k+m);
=>a = a/7;
=>a = 1;

--------------------------------------------------------------------------
5.
const
符号常量;
(1)const char *p
(2)char const *p
(3)char * const p
说明上面三种描述的区别;


如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;
如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。

(1)const char *p

一个指向char类型的const对象指针,p不是常量,我们可以修改p的值,使其指向不同的char,但是不能改变它指向非char对象,如:
const char *p;
char c1='a';
char c2='b';
p=&c1;//ok
p=&c2;//ok
*p=c1;//error

(2)char const *p
(3)char * const p

这两个好象是一样的,此时*p可以修改,而p不能修改。

(4)const char * const p
这种是地址及指向对象都不能修改。

--------------------------------------------------------------------------
6.
下面是C语言中两种if语句判断方式。请问哪种写法更好?为什么?
 int n;
 if (n == 10) //
第一种判断方式
 if (10 == n) //
第二种判断方式

如果少了个=,编译时就会报错,减少了出错的可能行,可以检测出是否少了=

--------------------------------------------------------------------------
7.
下面的代码有什么问题?
void DoSomeThing(...)
{
 char* p;
 ...
 p = malloc(1024);  //
分配1K的空间
 if (NULL == p)
  return;
 ...
 p = realloc(p, 2048); //
空间不够,重新分配到2K
 if (NULL == p)
  return;
 ...
}

A:
p = malloc(1024);    
应该写成: p = (char *) malloc(1024);
       
没有释放p的空间,造成内存泄漏。


--------------------------------------------------------------------------
8.
下面的代码有什么问题?并请给出正确的写法。
void DoSomeThing(char* p)
{
 char str[16];
 int n;
 assert(NULL != p);
 sscanf(p, "%s%d", str, n);
 if (0 == strcmp(str, "something"))
 {
  ...
 }
}

A:
sscanf(p, "%s%d", str, n);  
这句该写成: sscanf(p, "%s%d", str, &n);

--------------------------------------------------------------------------
9.
下面代码有什么错误?
Void test1()
{
 char string[10];
 char *str1="0123456789";
 strcpy(string, str1);
}

数组越界

--------------------------------------------------------------------------
10.
下面代码有什么问题?
Void test2()
{
  char string[10], str1[10];
  for(i=0; i<10;i++)
  {
     str1[i] ='a';
  }
  strcpy(string, str1);
}

数组越界

--------------------------------------------------------------------------
11.
下面代码有什么问题?
Void test3(char* str1)
{
  char string[10];
  if(strlen(str1)<=10)
  {
    strcpy(string, str1);
  }
}

==数组越界
==strcpy
拷贝的结束标志是查找字符串中的\0 因此如果字符串中没有遇到\0的话会一直复制,直到遇到\0,上面的123都因此产生越界的情况
 
建议使用 strncpy memcpy

--------------------------------------------------------------------------
12.
下面代码有什么问题?

#define MAX_SRM 256

DSN get_SRM_no()
{
  static int SRM_no; //
是不是这里没赋初值?
  int I;
  for(I=0;I  {
    SRM_no %= MAX_SRM;
    if(MY_SRM.state==IDLE)
    {
      break;
    }
  }
  if(I>=MAX_SRM)
    return (NULL_SRM);
  else
    return SRM_no;
}

系统会初始化static int变量为0,但该值会一直保存,所谓的不可重入...

--------------------------------------------------------------------------
13.
写出运行结果:
{// test1
    char str[] = "world"; cout << sizeof(str) << ": ";
    char *p    = str;     cout << sizeof(p) << ": ";
    char i     = 10;      cout << sizeof(i) << ": ";
    void *pp   = malloc(10);  cout << sizeof(p) << endl;
}

6414

--------------------------------------------------------------------------
14.
写出运行结果:
{// test2
    union V {
 struct X {
  unsigned char s1:2;
  unsigned char s2:3;
  unsigned char s3:3;
 } x;

 unsigned char c;
    } v;

    v.c = 100;
    printf("%d", v.x.s3);

}

3

--------------------------------------------------------------------------
15.
C++写个程序,如何判断一个操作系统是16位还是32位的?不能用sizeof()函数

A1:
16
位的系统下,
int i = 65536;
cout << i; //
输出0
int i = 65535;
cout << i; //
输出-1

32位的系统下,
int i = 65536;
cout << i; //
输出65536
int i = 65535;
cout << i; //
输出65535

A2:

int a = ~0;
if( a>65536 )
{
    cout<<"32 bit"<}
else
{
    cout<<"16 bit"<}


--------------------------------------------------------------------------
16.C
C++有什么不同?

从机制上:c是面向过程的(但c也可以编写面向对象的程序);c++是面向对象的,提供了类。但是,
c++
编写面向对象的程序比c容易

从适用的方向:c适合要求代码体积小的,效率高的场合,如嵌入式;c++适合更上层的,复杂的;  llinux核心大部分是c写的,因为它是系统软件,效率要求极高。

从名称上也可以看出,c++c多了+,说明c++c的超集;那为什么不叫c+而叫c++呢,是因为c++
c
来说扩充的东西太多了,所以就在c后面放上两个+;于是就成了c++

C语言是结构化编程语言,C++是面向对象编程语言。
C++
侧重于对象而不是过程,侧重于类的设计而不是逻辑的设计。

--------------------------------------------------------------------------
17.
在不用第三方参数的情况下,交换两个参数的值
#include

void main()
{
        int i=60;
        int j=50;
        i=i+j;
        j=i-j;
        i=i-j;
        printf("i=%d\n",i);
        printf("j=%d\n",j);
}

方法二
i^=j;
j^=i;
i^=j;

方法三:
//
用加减实现,而且不会溢出
a = a+b-(b=a)

--------------------------------------------------------------------------
18.
有关位域的面试题(为什么输出的是一个奇怪的字符)

a.t = 'b';效果相当于 a.t= 'b' & 0xf;

'b' --> 01100010
'b' & 0xf -->>00000010
所以输出Ascii码为2的特殊字符


char t:4;就是4bit的字符变量,同样
unsigned short i:8;
就是8bit的无符号短整形变量

--------------------------------------------------------------------------
19.int i=10, j=10, k=3; k*=i+j; k
最后的值是?

60

--------------------------------------------------------------------------
20.
进程间通信的方式有?

进程间通信的方式有共享内存, 管道 ,Socket ,消息队列 , DDE

--------------------------------------------------------------------------
21.
struct A
{
char t:4;
char k:4;
unsigned short i:8;
unsigned long m;
}
sizeof(A)=?
(不考虑边界对齐)

7

struct CELL             // Declare CELL bit field
{
   unsigned character  : 8;  // 00000000 ????????
   unsigned foreground : 3;  // 00000??? 00000000
   unsigned intensity  : 1;  // 0000?000 00000000
   unsigned background : 3;  // 0???0000 00000000
   unsigned blink      : 1;  // ?0000000 00000000
} screen[25][80];       // Array of bit fields
二、位结构
   
位结构是一种特殊的结构, 在需按位访问一个字节或字的多个位时, 位结构
比按位运算符更加方便。
   
位结构定义的一般形式为:
     struct
位结构名
{
         
数据类型 变量名: 整型常数
;
         
数据类型 变量名: 整型常数
;
     }
位结构变量
;
   
其中: 数据类型必须是int(unsignedsigned)。 整型常数必须是非负的整

, 范围是0~15, 表示二进制位的个数, 即表示有多少位。
   
变量名是选择项, 可以不命名, 这样规定是为了排列需要。
   
例如: 下面定义了一个位结构。
     struct{
          unsigned incon: 8;  /*incon
占用低字节的0~78*/
          unsigned txcolor: 4;/*txcolor
占用高字节的0~3位共4
*/
          unsigned bgcolor: 3;/*bgcolor
占用高字节的4~6位共3
*/
          unsigned blink: 1;  /*blink
占用高字节的第7
*/
     }ch;
   
位结构成员的访问与结构成员的访问相同。

   
例如: 访问上例位结构中的bgcolor成员可写成:
      ch.bgcolor
 
   
注意
:
    1.
位结构中的成员可以定义为unsigned, 也可定义为signed,  但当成员长

度为1, 会被认为是unsigned类型。因为单个位不可能具有符号。
    2.
位结构中的成员不能使用数组和指针, 但位结构变量可以是数组和指针,
如果是指针, 其成员访问方式同结构指针。

    3.
位结构总长度(位数), 是各个位成员定义的位数之和可以超过两个字
节。
    4.
位结构成员可以与其它结构成员一起使用。
   
例如:
     struct info{
          char name[8];
          int age;
          struct addr address;
          float pay;
          unsigned state: 1;
          unsigned pay: 1;
          }workers;
   
上例的结构定义了关于一个工人的信息。其中有两个位结构成员, 每个位结

构成员只有一位, 因此只占一个字节但保存了两个信息, 该字节中第一位表示工
人的状态, 第二位表示工资是否已发放。由此可见使用位结构可以节省存贮空间。


--------------------------------------------------------------------------
22.
下面的函数实现在一个固定的数上加上一个数,有什么错误,改正
int add_n(int n)
{
  static int i=100;
  i+=n;
  return i;
}

:
因为static使得i的值会保留上次的值。

去掉static就可了

--------------------------------------------------------------------------
23.
下面的代码有什么问题?
class A
{
public:
  A() { p=this; }
  ~A() { if(p!=NULL) { delete p; p=NULL; } }

  A* p;
};

:
会引起无限递归

--------------------------------------------------------------------------
24.
union a {
 int a_int1;
 double a_double;
 int a_int2;
};

typedef struct
{
 a a1;
 char y;
} b;

class c
{
 double c_double;
 b b1;
 a a2;

};

输出cout<的结果?

:
VC6
环境下得出的结果是32

:
(sun)VC6.0+win2k下做过试验
:
short - 2
int-4
float-4
double-8
指针-4

sizeof(union),以结构里面size最大的为unionsize

 

 

·                                 27.struct class 的区别
答案:struct 的成员默认是公有的,而类的成员默认是私有的。struct class 在其他方面是功能相当的。
从感情上讲,大多数的开发者感到类和结构有很大的差别。感觉上结构仅仅象一堆缺乏封装和功能的开放的内存位,而类就象活的并且可靠的社会成员,它有智能服务,有牢固的封装屏障和一个良好定义的接口。既然大多数人都这么认为,那么只有在你的类有很少的方法并且有公有数据(这种事情在良好设计的系统中是存在的!)时,你也许应该使用 struct 关键字,否则,你应该使用 class 关键字。 
28.
当一个类A 中没有生命任何成员变量与成员函数,这时sizeof(A)的值是多少,如果不是零,请解释一下编译器为什么没有让它为零。(Autodesk

答案:肯定不是零。举个反例,如果是零的话,声明一个class A[10]对象数组,而每一个对象占用的空间是零,这时就没办法区分A[0],A[1]…了。
29.
8086 汇编下,逻辑地址和物理地址是怎样转换的?(Intel
答案:通用寄存器给出的地址,是段内偏移地址,相应段寄存器地址*10H+通用寄存器内地址,就得到了真正要访问的地址。
30.
比较C++中的4种类型转换方式?
请参考:
http://blog.csdn.net/wfwd/archive/2006/05/30/763785.aspx,重点是static_cast, dynamic_castreinterpret_cast的区别和应用。
31.
分别写出BOOL,int,float,指针类型的变量a 与“零”的比较语句。
答案:
BOOL :    if ( !a ) or if(a)
int :     if ( a == 0)
float :   const EXPRESSION EXP = 0.000001
          if ( a < EXP && a >-EXP)
pointer : if ( a != NULL) or if(a == NULL)
 
32.
请说出const#define 相比,有何优点?
答案:1 const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。
      2
) 有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。
33.
简述数组与指针的区别?
数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。指针可以随时指向任意类型的内存块。
(1)
修改内容上的差别
char a[] =
hello;
a[0] =
X
;
char *p =
world; // 注意p 指向常量字符串

p[0] =
X; // 编译器不能发现该错误,运行时错误
(2)
用运算符sizeof 可以计算出数组的容量(字节数)。sizeof(p),p 为指针得到的是一个指针变量的字节数,而不是p 所指的内存容量。C++/C 语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。
char a[] = "hello world";
char *p = a;
cout<< sizeof(a) << endl; // 12
字节
cout<< sizeof(p) << endl; // 4
字节
计算数组和指针的内存容量
void Func(char a[100])
{
cout<< sizeof(a) << endl; // 4
字节而不是100 字节
}
34.
类成员函数的重载、覆盖和隐藏区别?
答案:
a.
成员函数被重载的特征:
1)相同的范围(在同一个类中);
2)函数名字相同;
3)参数不同;
4virtual 关键字可有可无。
b.
覆盖是指派生类函数覆盖基类函数,特征是:
1)不同的范围(分别位于派生类与基类);
2)函数名字相同;
3)参数相同;
4)基类函数必须有virtual 关键字。
c.
“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)
35. There are two int variables: a and b, don
t use if, ? :, switchor other judgement statements, find out the biggest one of the two numbers.
答案:
( ( a + b ) + abs( a - b ) ) / 2
36.
如何打印出当前源文件的文件名以及源文件的当前行号?

答案:
cout << __FILE__ ;
cout<<__LINE__ ;
__FILE__
__LINE__是系统预定义宏,这种宏并不是在某个文件中定义的,而是由编译器定义的。
37. main
主函数执行完毕后,是否可能会再执行一段代码,给出说明?
答案:可以,可以用_onexit 注册一个函数,它会在main 之后执行int fn1(void), fn2(void), fn3(void), fn4 (void);
void main( void )
{
String str("zhanglin");
_onexit( fn1 );
_onexit( fn2 );
_onexit( fn3 );
_onexit( fn4 );
printf( "This is executed first.\n" );
}
int fn1()
{
printf( "next.\n" );
return 0;
}
int fn2()
{
printf( "executed " );
return 0;
}
int fn3()
{
printf( "is " );
return 0;
}
int fn4()
{
printf( "This " );
return 0;
}
The _onexit function is passed the address of a function (func) to be called when the program terminates normally. Successive calls to _onexit create a register of functions that are executed in LIFO (last-in-first-out) order. The functions passed to _onexit cannot take parameters.
38.
如何判断一段程序是由C 编译程序还是由C++编译程序编译的?

答案:
#ifdef __cplusplus
cout<<"c++";
#else
cout<<"c";
#endif
39.
文件中有一组整数,要求排序后输出到另一个文件中
答案:
i nclude
i nclude
using namespace std;

void Order(vector& data) //bubble sort
{
int count = data.size() ;
int tag = false ; //
设置是否需要继续冒泡的标志位
for ( int i = 0 ; i < count ; i++)
{
for ( int j = 0 ; j < count - i - 1 ; j++)
{
if ( data[j] > data[j+1])
{
tag = true ;
int temp = data[j] ;
data[j] = data[j+1] ;
data[j+1] = temp ;
}
}
if ( !tag )
break ;
}
}

void main( void )
{
vectordata;
ifstream in("c:\\data.txt");
if ( !in)
{
cout<<"file error!";
exit(1);
}
int temp;
while (!in.eof())
{
in>>temp;
data.push_back(temp);
}
in.close(); //
关闭输入文件流
Order(data);
ofstream out("c:\\result.txt");
if ( !out)
{
cout<<"file error!";
exit(1);
}
for ( i = 0 ; i < data.size() ; i++)
out<<<" ";
out.close(); //
关闭输出文件流
}
 
40.
链表题:一个链表的结点结构
struct Node
{
int data ;
Node *next ;
};
typedef struct Node Node ;

(1)已知链表的头结点head,写一个函数把这个链表逆序 ( Intel)
Node * ReverseList(Node *head) //
链表逆序

{
if ( head == NULL || head->next == NULL )
return head;
Node *p1 = head ;
Node *p2 = p1->next ;
Node *p3 = p2->next ;
p1->next = NULL ;
while ( p3 != NULL )
{
p2->next = p1 ;
p1 = p2 ;
p2 = p3 ;
p3 = p3->next ;
}
p2->next = p1 ;
head = p2 ;
return head ;
}
(2)
已知两个链表head1 head2 各自有序,请把它们合并成一个链表依然有序。(保留所有结点,即便大小相同)
Node * Merge(Node *head1 , Node *head2)
{
if ( head1 == NULL)
return head2 ;
if ( head2 == NULL)
return head1 ;
Node *head = NULL ;
Node *p1 = NULL;
Node *p2 = NULL;
if ( head1->data < head2->data )
{
head = head1 ;
p1 = head1->next;
p2 = head2 ;
}
else
{
head = head2 ;
p2 = head2->next ;
p1 = head1 ;
}
Node *pcurrent = head ;
while ( p1 != NULL && p2 != NULL)
{
if ( p1->data <= p2->data )
{
pcurrent->next = p1 ;
pcurrent = p1 ;
p1 = p1->next ;
}
else
{
pcurrent->next = p2 ;
pcurrent = p2 ;
p2 = p2->next ;
}
}
if ( p1 != NULL )
pcurrent->next = p1 ;
if ( p2 != NULL )
pcurrent->next = p2 ;
return head ;
}
(3)
已知两个链表head1 head2 各自有序,请把它们合并成一个链表依然有序,这次要求用递归方法进行。 (Autodesk)
答案:

Node * MergeRecursive(Node *head1 , Node *head2)
{
if ( head1 == NULL )
return head2 ;
if ( head2 == NULL)
return head1 ;
Node *head = NULL ;
if ( head1->data < head2->data )
{
head = head1 ;
head->next = MergeRecursive(head1->next,head2);
}
else
{
head = head2 ;
head->next = MergeRecursive(head1,head2->next);
}
return head ;
}
41.
分析一下这段程序的输出 (Autodesk)
class B
{
public:
B()
{
cout<<"default constructor"<}
~B()
{
cout<<"destructed"<}
B(int i):data(i)    //B(int) works as a converter ( int -> instance of  B)
{
cout<<"constructed by parameter " << data <}
private:
int data;
};

B Play( B b)
{
return b ;
}
(1)                                            results:
int main(int argc, char* argv[])      constructed by parameter 5
{                                     destructed  B(5)
形参析构
B t1 = Play(5); B t2 = Play(t1);  
  destructed  t1形参析构
return 0;
               destructed  t2 注意顺序!
}                                     destructed  t1
(2)                                   results:
int main(int argc, char* argv[])      constructed by parameter 5
{                                     destructed  B(5)
形参析构
B t1 = Play(5); B t2 = Play(10);  
  constructed by parameter 10
return 0;
               destructed  B(10)形参析构

}                                     destructed  t2
 注意顺序!
                                      destructed  t1
42.
写一个函数找出一个整数数组中,第二大的数 (microsoft
答案:
const int MINNUMBER = -32767 ;
int find_sec_max( int data[] , int count)
{
int maxnumber = data[0] ;
int sec_max = MINNUMBER ;
for ( int i = 1 ; i < count ; i++)
{
if ( data
> maxnumber )
{
sec_max = maxnumber ;
maxnumber = data
;
}
else
{
if ( data
> sec_max )
sec_max = data
;
}
}
return sec_max ;
}
43.
写一个在一个字符串(n)中寻找一个子串(m)第一个位置的函数。
KMP
算法效率最好,时间复杂度是O(n+m)
44.
多重继承的内存分配问题:
  
比如有class A : public class B, public class C {}
  
那么A的内存结构大致是怎么样的?

这个是compiler-dependent, 不同的实现其细节可能不同。
如果不考虑有虚函数、虚继承的话就相当简单;否则的话,相当复杂。
可以参考《深入探索C++对象模型》,或者:
http://blog.csdn.net/wfwd/archive/2006/05/30/763797.aspx
45. 如何判断一个单链表是有环的?(注意不能用标志位,最多只能用两个额外指针)

   struct node { char val; node* next;}

   bool check(const node* head) {} //return false : 无环;true: 有环
一种On)的办法就是(搞两个指针,一个每次递增一步,一个每次递增两步,如果有环的话两者必然重合,反之亦然):
bool check(const node* head)
{
    if(head==NULL)  return false;
    node *low=head, *fast=head->next;
    while(fast!=NULL && fast->next!=NULL)
    {
        low=low->next;
        fast=fast->next->next;
        if(low==fast) return true;
    }
    return false;
}

 

文章引用自:

 

阅读(851) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~