C++学习(36)
2017-06-09 15:35
183 查看
1.一个C++程序是由一个或多个函数所组成,即使是最简单的程序,也必须有一个main函数。该函数是程序执行的起点和终点。C++中,函数不允许嵌套定义,允许嵌套调用。
2.下列程序输出结果为:22
#include<iostream>
#include<string.h>
#pragma pack(2)
using namespace std;
class A{
int i;
union U{
char buff[13];
int i;
}u;
void foo(){
}
typedefchar*(*f)(void);
enum{red,green,blue}color;
};
int main() {
cout<<sizeof(A);
return 0;
}对于第一条原则,每个变量相对于结构体的首地址的偏移量必须是对齐参数的整数倍,这句话中的对齐参数是取每个变量自身对齐参数和系统默认对齐参数#pragmapack(n)中较小的一个;
对于第二条原则,结构体变量所占空间的大小是对齐参数的整数倍。这句话中的对齐参数有点复杂,它是取结构体中所有变量的对齐参数的最大值和系统默认对齐参数#pragma pack(n)比较,较小者作为对齐参数。
关于那个函数指针的问题,如果不加typedef,就是说这是类本身的函数指针,需要计算指针占用空间;如果加上typedef,说明这只是该函数指针的别名,不是类自己的指针
3.下列程序输出的是:A
#include<iostream>
#include<string.h>
#pragma pack(2)
using namespace std;
class A{
public:
void f(){
cout<<"A"<<endl;
}
};
class B:public A {
public:
virtual void f(){
cout<<"B"<<endl;
}
};
int main() {
A *a=new B;
a->f();
delete a;
return 0;
}
分析:基类A中声明为虚函数,才会被B覆盖,而虚函数调用的方法是看对象的,即如果A中f声明为虚函数,那么应该调用B的f才对。此处没有覆盖,应该根据指针或者引用来看调用的方法。
4.下列程序输出:乱码
#include<iostream>
#include<string.h>
using namespace std;
char * getmemory(void) {
charp[]="hello world";
return p;
}
void test(void) {
char *str=NULL;
str=getmemory();
printf(str);
}
int main() {
test();
return 0;
}分析:getmemory()返回的指针,是内部变量,调用之后会被回收。所以输出是不确定的。如果将char p[]="hello world";改成 char *p="helloworld";就可以输出helloworld、
返回“字符串常量指针”和“返回数组名”的区别在于,一个返回静态数据区的地址,一个返回栈内存(动态数据区)的地址。
5.下列程序输出:不确定。
#include<iostream>
#include<string.h>
using namespace std;
char * getmem(void) {
char p[]="hello world";
p[5]=0x0;
return p;
}
void test(void) {
char *s=0x0;
s=getmem();
}
int main() {
test();
return 0;
}
分析:Warning:address of localvariable’p’ returned.
p是个数组,在{}里面定义是个局部变量,说明这个函数执行完毕之后局部变量销毁p这个数组中的值都没有了。
p虽然是个数组,但是单独用p这个变量,值是p这块数组的首地址,因为返回的是值传递,所以这个首地址被传到了下面的s中。
s指向这个内存,而这个内存在getMem函数调用结束后就销毁了,里面存放的不知道是什么了。所以打印的话不一定出现什么。
6.对于protected成员,错误的是(A)
A
基类可以访问从所有派生类造型(cast)成基类对象的protected成员;
B
从派生类继承的子类可以访问基类的protected成员;
C
派生类可以定义一个同名的非protected成员;
D
派生类可以访问基类对象的protected成员;
分析:派生类强制转化成基类(dynamic_cast)会做相应成员变量和函数的裁剪,仅能访问从基类继承来的部分成员。
派生类如果要访问基类protected成员只有通过派生类对象,派生类不能访问基类对象的protected成员;
7.
如果只是论一个汉字占用的字节数,那么
UTF-8占用3个字节,UTF-16占用2个字节。但是如果存储文本的话,需要在文本使用EF BB
BF 三个字节表示使用UTF-8编码,使用FE FF表示使用UTF-16编码。
UTF-16固定表示两个字节表示一个字符,不管是字母还是汉字;UTF-8使用3个字节表示一个字符。
0xxxxxxx
一个字节兼容ASCII,能表示127个字符 110xxxxx 10xxxxxx.如果是这样的格式,则把两个字节当一个字符 1110xxxx 10xxxxxx 10xxxxxx 如果是这种格式则是三个字节当一个字符。
所以,UTF-8的空间是根据保存的内容不同而不同。如果保存的汉字多,使用 UTF-16 占用字符数双倍的空间,使用 UTF-8 占用字符数三倍的空间;如果保存的英文字母多,使用 UTF-16 使用字符数双倍的空间,使用 UTF-8 使用字符数相同的空间。
8.
C++在编译前由预处理器对预处理命令进行处理,编译时进行语法分析。
9.若有定义语句:char s[3][10],(*k)[3],*p;则以下赋值语句错误的是(124)
1).p=s; 2)p=k; 3)p=s[0];4)k=s;
分析:s是一个二维数组,但也可以看成是一个包含3个元素的一维数组,每个元素又是一个包含10个元素的一维数组。s这个名字本身的值是指向它第一个元素的指针。也就是说,s的值是指向包含3个元素的一维数组的第一个元素的指针。即第一个包含10个元素的一维数组的指针。k是一个指针,而不是指针数组。k指向一个包含3个元素的一维数组的指针。
简单说,s是指向一维数组的常量指针,数组包含10个元素。k是指向一维数组的变量指针,数组包含3个元素。而p是指向单个变量的指针。如果一个变量算一个单位长,那么s+1就意味着指针走了10个单位长,k+1就意味着走了3个单位长,p+1就意味着走了1个单位长。
指针不仅仅是地址,它还包括它所指向的类型,这样才能知道下一步它自己要走多长。
把C语言到汇编语言看成一个加工过程,C程序就是原材料,编译器就是加工厂,汇编程序就是产品。C语言的内容就包括两部分,一部分是给编译器加工用的信息,一部分就是留下的产品。C语言中很多都是两层含义的,比如程序中写了int
m; 一般书上说int m 既是声明也是定义。声明说的是给编译器的信息,定义说的是给汇编程序的信息。同样,指针也是两层意思,一层是供编译器加工用的(指针的步长应该就是你所说的上下文吧),一层是给汇编程序的(内存)。不能把指针看成一个类型,而应该看成一系列类型!正如int和float是两个类型一样(虽然它们的内存大小都是4字节),int*
和float*也是两个类型(但是它们很相似,都是内存大小一样,所存放的数据又都是地址值,所以才会容易被混为一谈)。
2.下列程序输出结果为:22
#include<iostream>
#include<string.h>
#pragma pack(2)
using namespace std;
class A{
int i;
union U{
char buff[13];
int i;
}u;
void foo(){
}
typedefchar*(*f)(void);
enum{red,green,blue}color;
};
int main() {
cout<<sizeof(A);
return 0;
}对于第一条原则,每个变量相对于结构体的首地址的偏移量必须是对齐参数的整数倍,这句话中的对齐参数是取每个变量自身对齐参数和系统默认对齐参数#pragmapack(n)中较小的一个;
对于第二条原则,结构体变量所占空间的大小是对齐参数的整数倍。这句话中的对齐参数有点复杂,它是取结构体中所有变量的对齐参数的最大值和系统默认对齐参数#pragma pack(n)比较,较小者作为对齐参数。
关于那个函数指针的问题,如果不加typedef,就是说这是类本身的函数指针,需要计算指针占用空间;如果加上typedef,说明这只是该函数指针的别名,不是类自己的指针
3.下列程序输出的是:A
#include<iostream>
#include<string.h>
#pragma pack(2)
using namespace std;
class A{
public:
void f(){
cout<<"A"<<endl;
}
};
class B:public A {
public:
virtual void f(){
cout<<"B"<<endl;
}
};
int main() {
A *a=new B;
a->f();
delete a;
return 0;
}
分析:基类A中声明为虚函数,才会被B覆盖,而虚函数调用的方法是看对象的,即如果A中f声明为虚函数,那么应该调用B的f才对。此处没有覆盖,应该根据指针或者引用来看调用的方法。
4.下列程序输出:乱码
#include<iostream>
#include<string.h>
using namespace std;
char * getmemory(void) {
charp[]="hello world";
return p;
}
void test(void) {
char *str=NULL;
str=getmemory();
printf(str);
}
int main() {
test();
return 0;
}分析:getmemory()返回的指针,是内部变量,调用之后会被回收。所以输出是不确定的。如果将char p[]="hello world";改成 char *p="helloworld";就可以输出helloworld、
返回“字符串常量指针”和“返回数组名”的区别在于,一个返回静态数据区的地址,一个返回栈内存(动态数据区)的地址。
5.下列程序输出:不确定。
#include<iostream>
#include<string.h>
using namespace std;
char * getmem(void) {
char p[]="hello world";
p[5]=0x0;
return p;
}
void test(void) {
char *s=0x0;
s=getmem();
}
int main() {
test();
return 0;
}
分析:Warning:address of localvariable’p’ returned.
p是个数组,在{}里面定义是个局部变量,说明这个函数执行完毕之后局部变量销毁p这个数组中的值都没有了。
p虽然是个数组,但是单独用p这个变量,值是p这块数组的首地址,因为返回的是值传递,所以这个首地址被传到了下面的s中。
s指向这个内存,而这个内存在getMem函数调用结束后就销毁了,里面存放的不知道是什么了。所以打印的话不一定出现什么。
6.对于protected成员,错误的是(A)
A
基类可以访问从所有派生类造型(cast)成基类对象的protected成员;
B
从派生类继承的子类可以访问基类的protected成员;
C
派生类可以定义一个同名的非protected成员;
D
派生类可以访问基类对象的protected成员;
分析:派生类强制转化成基类(dynamic_cast)会做相应成员变量和函数的裁剪,仅能访问从基类继承来的部分成员。
派生类如果要访问基类protected成员只有通过派生类对象,派生类不能访问基类对象的protected成员;
7.
如果只是论一个汉字占用的字节数,那么
UTF-8占用3个字节,UTF-16占用2个字节。但是如果存储文本的话,需要在文本使用EF BB
BF 三个字节表示使用UTF-8编码,使用FE FF表示使用UTF-16编码。
UTF-16固定表示两个字节表示一个字符,不管是字母还是汉字;UTF-8使用3个字节表示一个字符。
0xxxxxxx
一个字节兼容ASCII,能表示127个字符 110xxxxx 10xxxxxx.如果是这样的格式,则把两个字节当一个字符 1110xxxx 10xxxxxx 10xxxxxx 如果是这种格式则是三个字节当一个字符。
所以,UTF-8的空间是根据保存的内容不同而不同。如果保存的汉字多,使用 UTF-16 占用字符数双倍的空间,使用 UTF-8 占用字符数三倍的空间;如果保存的英文字母多,使用 UTF-16 使用字符数双倍的空间,使用 UTF-8 使用字符数相同的空间。
8.
C++在编译前由预处理器对预处理命令进行处理,编译时进行语法分析。
9.若有定义语句:char s[3][10],(*k)[3],*p;则以下赋值语句错误的是(124)
1).p=s; 2)p=k; 3)p=s[0];4)k=s;
分析:s是一个二维数组,但也可以看成是一个包含3个元素的一维数组,每个元素又是一个包含10个元素的一维数组。s这个名字本身的值是指向它第一个元素的指针。也就是说,s的值是指向包含3个元素的一维数组的第一个元素的指针。即第一个包含10个元素的一维数组的指针。k是一个指针,而不是指针数组。k指向一个包含3个元素的一维数组的指针。
简单说,s是指向一维数组的常量指针,数组包含10个元素。k是指向一维数组的变量指针,数组包含3个元素。而p是指向单个变量的指针。如果一个变量算一个单位长,那么s+1就意味着指针走了10个单位长,k+1就意味着走了3个单位长,p+1就意味着走了1个单位长。
指针不仅仅是地址,它还包括它所指向的类型,这样才能知道下一步它自己要走多长。
把C语言到汇编语言看成一个加工过程,C程序就是原材料,编译器就是加工厂,汇编程序就是产品。C语言的内容就包括两部分,一部分是给编译器加工用的信息,一部分就是留下的产品。C语言中很多都是两层含义的,比如程序中写了int
m; 一般书上说int m 既是声明也是定义。声明说的是给编译器的信息,定义说的是给汇编程序的信息。同样,指针也是两层意思,一层是供编译器加工用的(指针的步长应该就是你所说的上下文吧),一层是给汇编程序的(内存)。不能把指针看成一个类型,而应该看成一系列类型!正如int和float是两个类型一样(虽然它们的内存大小都是4字节),int*
和float*也是两个类型(但是它们很相似,都是内存大小一样,所存放的数据又都是地址值,所以才会容易被混为一谈)。
相关文章推荐
- C++学习笔记36——赋值操作符
- C++学习之路(36)--- NULL、0、nullptr 区别分析
- C++学习笔记36 模版的显式具体化(template specialization)和显式实例化(template instantiation)
- 学习笔记36-C++ 智能指针
- C++学习笔记36 (模板的细节明确template specialization)和显式实例(template instantiation)
- C++学习历程
- C++学习手记(一)——初印象
- 学习C++(一) 我现在理解的C++
- C++学习笔记二 —— 3.3 指针类型
- 刚才在论坛上看到的一些学习C++的东东,可能对初学有点用
- c++入门学习笔记指针篇
- 开篇,从Kingofark那转过来的 关于学习C++和编程的50个观点 2003修订版
- 学习C++(二) 书的诱惑
- C++学习手记(三)——构造与析构
- C++学习笔记一 —— 3.5 const限定修饰符
- c++入门学习笔记--类和对象
- C++、C++学习之我见
- 一个C++程序员的Delphi学习笔记
- c++入门学习笔记继承
- C++学习要点