//***********************************************************
char *c[] = { "ENTER", "NEW", "POINT", "FIRST" };
char **cp[] = { c+3, c+2, c+1, c };
char ***cpp = cp;
c是一个指针数组,每个数组单元都是一个指针,指向一个字符串. c[0]="ENTER"......c[3]="FIRST"
由于[]与*运算本质几乎是一致的,以下用[]替换*更容易理解。
c[i]=*(c+i)
c和c+i都是char*[]类型,它可以退化成char**类型,它正好是一个char**数组 cp[0]=c+3 .....cp[3]=c
引用后cp[0][0]=*(c+3)=c[3]="FIRST"
cp是char**[]类型,它可以退化成char***类型,正好与cpp类型一致。
//*******************************
int const c=21; //变量c的值不能改变
const int *d=&a; //指针变量d指向的值不能改变
int *const e=&b; //指针的指向不能改变
int const *f const =&a; //指针不能改变,指针指向的值也不能改变。
const 读取方法
如: int const * const p;
找到第一个const, 后面除了有个const之外 就是 * 和 p,那么见证奇迹的时刻来了,
const * p 这就是我们要的结果,p指向的内容不可变
找到第二个const, 后面只有个p, 那么见证奇迹的时候到了
const p,,这就是结果, p不可变
++规则总结如下:找到const, 再看后面除了const的内容,是什么东西,那个东西不能变即是
//***多维数组*****
已知int a[3][4];则下列能表示a[1][2]元素值的是
*(*(a+1)+2)
在多维数组中,数组名是第一个数组的地址.
注意:这里a不是第一个元素的地址,而是第一个维数组的地址,a[0][0]才是表示的一维数组第一个元素的地址.
地址 + 1表示向下移一层. 到第二个数组地址
*(a+1)表示第二行的首地址,和a[1]一样。
*(a+1)+2第二行第三个数字的地址
*(*(a+1)+2)就是第二行第三个数字的值
//*******类的概念***
在C++面向对象编程语言中,以下阐述不正确的是:
a接口中可以用虚方法
b.一个类可以实现多个接口
c.接口不能被实例化
d.接口中可以包含已经实现的方法
首先所谓的接口是指只包含纯虚函数的抽象类,和普通的抽象类不一样。
所以A不对,必须是纯虚函数。
然后B是正确的没有问题。
刚才说接口是特殊的抽象类,抽象类的唯一作用就是创建派生类,不能定义抽象类的对象,所以C是正确的。
对于D,接口即只包含纯虚函数的抽象类,所以D是不对的
//*********************
char a=101;
int sum=200;
a+=27;sum+=a;
printf("%d\n",sum);
char为有符号类型,占1个字节,也就是8位,其中最高位位符号位,取值范围为-128~127;
a=101+27=128>127; 表示为1000 0000,计算机中以补码形式存储, 即为-128;
sum=200+(-128)=72;
//*****C++中的结构体和类的比较***
在C语言中结构体是不能继承的,但是在C++中也有结构体的概念。
区别:
结构体继承的默认访问权限为public,类继承的默认访问权限为private。
C++中结构体的成员变量访问权限也有三种:pubic、protected、private,默认访问权限是public;但类的默认访问权限是private。
相同:
可以有数据成员,方法,构造函数等。
void GetMemory(char *p)
{
p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
GetMemory(char *p);这里*p是形参,是局部变量
不能将malloc申请的地址指针返回,造成内存泄露
更严重的是执行GetMemory(str);后str依然为NULL 。执行strcpy(str, 'hello world');就会出错
传指针是可以通过指针的指向来改变变量的值,但是由于传入的是指针本身的副本,指针本身的值并不改变。
C++将父类的析构函数定义为虚函数,作用有:
释放子类指针时能正确释放父类对象。
C++中假设有基类为fa,它的派生类为son,
*fa = new son();
如果有基类的析构函数不是虚函数。在delete fa或者释放*fa的时候将只会调用基类的析构函数;
如果基类的析构函数为虚函数,在delete fa或者释放*fa的时候会先调用派生类(这里也就是son)的析构函数,再调用基类的析构函数。
void main()
{
int a[5] = { 1,2,3,4,5 };
int *p = (int *)(&a + 1);
printf("%d", *(p - 1));
system("pause");
}
数组名a可以作为数组的首地址,而&a是数组的指针。
int *p=(int *)(&a+1);//这条语句中&a代表整个数组的地址,+1应加上sizeof(a)的长度,故指针p指向a[5]处。
printf("%d",(*p-1));//(*p-1) == a[4],语句输出a[4]的值,为5
struct Node
{
int size;
char data[0];
};
char data[0];百度 柔性数组,
它只能放在结构体末尾,是申明一个长度为0的数组,就可以使得这个结构体是可变长的。
柔性数组(Flexible Array)也叫伸缩性数组,也就是变长数组,反映了C语言对精炼代码的极致追求。
这种代码结构产生于对动态结构体的需求, 比如我们需要在结构体中存放一个动态长度的字符串时,就可以用柔性数组。
C99使用不完整类型来实现柔性数组,标准形式如下:
struct MyStruct
{
int a;
double b;
char c[]; // or char c[0]; 也可以用其他数据类型;
};
数组c 不占用MyStruct的空间,只是作为一个符号地址存在,而且必须是结构体的最后一个成员。
(1) 什么是类模板
一个类模板(也称为类属类或类生成类)允许用户为类定义一种模式,
使得类中的某些数据成员、默写成员函数的参数、某些成员函数的返回值,能够取任意类型(包括系统预定义的和用户自定义的)。
如果一个类中数据成员的数据类型不能确定,或者是某个成员函数的参数或返回值的类型不能确定,就必须将此类声明为模板,它的存在不是代表一个具体的、实际的类,而是代表着一类类。
(2)类模板定义
定义一个类模板,一般有两方面的内容:
A.首先要定义类,其格式为:
template <class T>
class foo
{
……
}
foo 为类名,在类定义体中,如采用通用数据类型的成员,函数参数的前面需加上T,其中通用类型T可以作为普通成员变量的类型,还可以作为const和static成员变量以及成员函数的参数和返回类型之用。例如:
template<class T>
class Test{
private:
T n;
const T i;
static T cnt;
public:
Test():i(0){}
Test(T k);
~Test(){}
void print();
T operator+(T x);
};
B. 在类定义体外定义成员函数时,若此成员函数中有模板参数存在,则除了需要和一般类的体外定义成员函数一样的定义外,还需在函数体外进行模板声明
例如
template<class T>
void Test<T>::print(){
std::cout<<"n="<<n<<std::endl;
std::cout<<"i="<<i<<std::endl;
std::cout<<"cnt="<<cnt<<std::endl;
}
如果函数是以通用类型为返回类型,则要在函数名前的类名后缀上“<T>”。例如:
template<class T>
Test<T>::Test(T k):i(k){n=k;cnt++;}
template<class T>
T Test<T>::operator+(T x){
return n + x;
}
C. 在类定义体外初始化const成员和static成员变量的做法和普通类体外初始化const成员和static成员变量的做法基本上是一样的,唯一的区别是需再对模板进行声明,例如
template<class T>
int Test<T>::cnt=0;
template<class T>
Test<T>::Test(T k):i(k){n=k;cnt++;}
(3)类模板的使用
类模板的使用实际上是将类模板实例化成一个具体的类,它的格式为:类名<实际的类型>。
模板类是类模板实例化后的一个产物。例子:
template<class T>
class Foo {
T tVar;
public:
Foo(T t) : tVar(t) { }
};
class FooDerived : public Foo<int> {
public:
FooDerived() :Foo<int>(12) {
}
};
//Foo<int> 或 Foo<double> 就是两个Foo的模板类。 可以直接生成对象 Foo<int> fi; Foo<double> fd; 都正确
//************
声明一个数组指针,随便来一个数组指针是 int(*p)[10]
声明一个函数指针,随便来一个函数指针 int (*pf)(int *)
题目:声明一个指向含有10个元素的数组的指针,其中每个元素是一个函数指针,该函数的返回值是int,参数是int*,正确的是()
int (*(*p)[10])(int *)
解析:
先看未定义标识符p,p的左边是*,*p表示一个指针,跳出括号,由于[]的结合性大于*,所以*p指向一个大小为10的数组,即(*p)[10]。左边又有一个*号,修释数组的元素,*(*p)[10]表示*p指向一个大小为10的数组,且每个数组的元素为一个指针。跳出括号,根据右边(int *)可以判断(*(*p)[10])是一个函数指针,该函数的参数是int*,返回值是int。