C++学习(36)

本文深入探讨了C++编程中的关键概念,包括函数定义、内存管理、类与对象的使用等,并通过具体示例讲解了如何正确处理内存分配、函数指针及派生类访问等问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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*也是两个类型(但是它们很相似,都是内存大小一样,所存放的数据又都是地址值,所以才会容易被混为一谈)。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值