(1)、const char *p
(2)、char const *p
(3)、char * const p
如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量。
如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。
析构函数的作用是当对象生命期结束时释放对象所占用的资源。析构函数用法:析构函数是特殊的类成员函数
它的名字和类名相同,没有返回值,没有参数不能随意调用也没有重载。只是在类对象生命期结束时有系统自动调用。
虚函数用在继承中,当在派生类中需要重新定义基类的函数时需要在基类中将该函数声明为虚函数,作用为使程序支持动态联遍。
栈(stack):由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
堆:一般由程序员分配释放,若不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式类似。
BOOL:If(flag)或if(!flag)
Float:const float EPSINON = 0.00001;
If((x>=.EPSINON)&&(x<=EPSINON)) 说明:不可将浮点变量用”==”或”!=”与数字比较,应该设法转化成”>=”或”<=”此类形式。
指针*p:if(p==NULL) if(p!=NULL)
Char str[] = “Hello”;
Char *p = str;
Int n = 10
请计算:
Sizeof(str) = 6
Sizeof(p) = 4
Sizeof(n)=2
Void Func(char str[100])
{
请计算:sizeof(str) = 4
}
Void *p = malloc(100)
请计算:sizeof(p) = 4
对于#include <filename.h>,编译器从标准库路径开始搜索filename.h,对于#include “filename.h”,编译器从用户的工作路径中开始搜索filename.h
C++语言支持函数重载,C语言不支持函数重载。函数被C++编译后在库中的名字与C语言的不同。假设某个函数的原型为:void fee(int x,inty);
该函数被C编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。
C++提供了C连接交换指定符号extern “C”来解决名字匹配的问题。
Void GetMemory(char *p)
{
P = (char *)malloc(100);
}
Void Test(void)
{
Char *str = NULL;
GetMemory(str);
Strcpy(str,”hello world”);
Printf(str);
}//函数内的变量是独立于main的,对其改变不会影响main的变量
请问运行Test函数会有什么样的结果?
程序会崩溃,因为GetMemory并不能传递动态内存,Test函数中的str一直是NULL。
Strycpy(str,”hello world”);将使程序崩溃。
Char *GetMemory(void)
{
Char p[] = “hello world”;
Return p;
}
Void Test(void)
{
Char *str = NULL;
Str = GetMemory();
Printf(str);
}
请问Test函数会有什么样的结果?
可以是乱码。因为GetMemory返回的是指向”栈内存”的指针,该指针的地址不是NULL,但其原现的内容已经被清除,新内容不知。
Void GetMemory2(char **p,int num)
{
*P = (char *)malloc(num);
}
Void Test(void)
{
Char *str = NULL;
GetMemory(&str,100);
Strcpy(str,”hello”);
Printf(str);
}
请问运行Test函数会有什么样的结果?
Void Test(void)
{
Char *str = (char *) malloc(100);
Strcpy(str,”hello”);
Free(str);
If(str != NULL)
{
Strcpy((str,”world”);
Printf(str);
}
}
请问运行Test函数会有什么样的结果?
篡改动态内存区的内容,后果难以预料,非常危险。
因为free(str);之后,str成为野指针,if(str!=NULL)语句不起作用。
在运行C++程序时,通常从main()函数开始执行。因此如果没有main(),程序将不完整,编译器将指出未定义main()函数。
例外情况:如,在windows编程中,可以编写一个动态 连接库(DLL)模块,这是其他windows程序可以使用的代码。由于DLL模块不是独立的程序,因此不需要main()。用于专用环境的程序――如机器人中的控制器芯片――可能不需要main(),但常规的独立程序都需要main().
从编译原理上来说,声明是仅仅告诉编译器,有个某类型的变量会被使用,但是编译器并不会为它分配任何内存。而定义就是分配了内存。
1、Sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小。
2、Sizeof是运算符,strlen是函数
3、Sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以换行符”\0″结尾的。
4、Strlen的结果要在运行的时候才能计算出来,是用来计算字符串的长度,不是类型占内存的大小。
5、数组做sizeof的参数不退化,传递给strlen就退化为指针;
New有三个字母,malloc有六个字母
New可以认为是malloc加构造函数的执行。
New出来的指针是直接带类型信息。
而malloc返回的都是void指针。
#define指示接受一个名字并定义该名字为预处理器变量;
#ifndef检测指定的预处理变量是否定义;
#endif预处理未定义
答:双向链表删除一个节点P
Template<class type> void list<type>::delnode(int p)
{
int k = 1;
listnode<type> *ptr,*t;
ptr = first;
While(ptr->next!=NULL&&k!=p)
{
ptr = ptr->next;
k++;
}
t = ptr->next;
cout <<”你已经将数据项”<<t->data<<”删除”<<endl;
ptr->next = ptr->next->next;
length–;
delte t;
}
在节点P后插入一个节点:
Template<class type> bool list<type>::insert(type t,int p)
{
Listnode<type> *ptr;
Ptr = first;
int k = 1;
while(ptr != NULL && k < p)
{
ptr = ptr->next;
k++;
}
If(ptr == NULL && k!=p)
{
return false;
}
else
{
Listnode<type> *tp;
tp = new listnode<type>;
tp->data = t;
tp->next = ptr->next;
ptr->next = tp;
length++;
return true;
}
}
sizeof操作符一个主要用途是存储分配和I/O系统那样的例程进行通信。可以查看某种类型的对象在内存中所占单位字节;
在动态分配一对象时,可以让系统指导要分配多少内存;
便于一些类型的扩充。
struct Test
{
Test(int){};
Test(){};
void fun(){};
};
void main(void)
{
Test a(1);
a.fun();
Test b();
b.fun();
}
Test b();//定义了一个函数 b不是一个类对象。
Cout <<(true?1:”I”<<endl;
1:”1″不是同一类型
:前后必须是同一类型or能隐式转换的类型
char str1[] = “abc”;
char str2[] = “abc”;
const char str3[] = “abc”;
const char str4[]] = “abc”;
const char* str5 = “abc”;
const char* str6 = “abc”;
cout << boolalpha <<(str==str2)<<endl;
cout <<boollalpha<<(str3==str4)<<endl;
cout <<boollalpha<<(str5==str6)<<endl;
分别输出false,false,true。Str1和str2都是字符数组,每个都有其自己的存储区,它们的值则是各存储区的首地址,不符;str3和str4同上,只是按const语义,它们所指向的数组区不能修改。Str5和str6并非数组而是字符指针,并不分配存储区,其后”abc”以常量形式存于静态数据区,而它们自己仅是指向该区首地址的指针,相符。
class Empty
{
public:
Empty();//缺省构造函数
Empty(const Empty&);//拷贝构造函数
~Empty();//析构函数
Empty&operator=(const Empty&);//赋值运算符
Empty* operator&(); //取址运算符
Const Empty* operator&() const;//取址运算符 const
};
unsigned int const size1 = 2;
char str1[size1];
unsigned int temp = 0;
cin >>temp;
unsigned int const size2 = temp;
char str2[size2];
str2定义出错,size2非编译器期间常量,而数组定义要求长度必须编译期常量。
已知strcpy函数的原型是
char *strcpy(char *strDest,const char *strSrc);
其中strDest是目的字符串,strSrc是源字符串。
char *strcpy(char *strDest,const char *strSrc)
{
assert((strDest!=NULL)&&(strSrc!=NULL));
char *address = strDest;
while((*strDest ++=*strSrc++)!=’\0′)
{
NULL;
}
return address;
}
strycpy能把strSrc的内容复制到strDest,为什么还要char*类型的返回值?
为了实现链式表达式。
如:int length = strlen(strcpy(strDest,”hello world”));
#include <iostream>
Int main(void)
{
int a,b,c,d;
a = 10;
b = a++;
c = ++a;
d = 10 * a++;
printf(“b,c,d:%d,%d,%D”,a,b,c);
return 0;
}
10,12,120;
class String
{
public:
String(Const char *str = NULL);//普通构造函数
String(const String &other); //拷由构造函数
~String(void); //析构函数
String &operate = (const String &other);//赋值函数
private:
char *m_data;//用于保存字符串
};
//String的析构函数
String::~String(void)
{
delete[] m_data;//由于m_data是内部数据类型,也可以写成delete m_data;
}
//String的普通构造函数
String::String(const char *str)
{
If(str == NULL)
{
m_data = new char[1];
*m_data = ‘\0′;
}
else
{
int length = strlen(str);
m_data = new char[length + 1];
strcpy(m_data,str);
}
}
//拷贝构造函数
String::String(const String &other)
{
int length = strlen(other.m_data);
m_data = new char[length + 1];
strcpy(m_data,other.m_data);
}
//赋值函数
String&String::operate=(const String&other)
{
//1.检查自赋值
If(this == &other)\
return *this;
//2.释放原有的内存资源
Delete[] m_data;
//3.分配新的内存资源,并复制内容
int length = strlen(other.m_data);
m_data = new char[length+1];
strcpy(m_data,other.m_data);
return *this;
}
可以,在不同的C文件中以static形式来声明同名全局变更。可以在不同的C文件夹中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错。
C用宏定义,C++用inline
main()
{
int a[5] = {1,2,3,4,5};
int *ptr = (int *)(&a+1);
printf(“%d,%d”,*(a+1),*(ptr-1));
}
输出:2,5
*(a+1)就是a[1],*(ptr-1)就是a[4],执行结果是2,5;
&a+1不是首地址+1,系统会认为加一个a数组的偏移,是偏移了一个数组的大小(本例是5个int)
int *ptr = (int *)(&a+1);则ptr实际是&(a[5]),也就是a+5
原因如下:
&a是数组指针,其类型为int(*)[5];
而指针加1要根据指针类型加一定的值,不同类型的指针+1之后增加的大小不同,a是长度为5的int数组指针,所以要加5*sizeof(int)
所以ptr实际是a[5]
但是ptr与(&a+1)类型是不一样的(这点很重要)
所以ptr-1只会减去sizeof(int*)
a,&a的地址是一样的,但意思不一样,a是数组首地址,也就是a[0]的地址,&a是对象(数组)首地址,a+1是数组下一元素的地址,即a[1],&a+1是下一个对象的地址,即a[5].
sizeof如用于数组,只能测出静态数组的大小,无法检测动态分配的或外部数组大小。注意:数组名作为函数参数时,退化为指针。数组名作为sizeof()参数时,数组名不退化,因为sizeof不是函数。
int main()
{
char a;
char *str = &a;
strcpy(str,”hello”);
printf(str);
return 0;
}
没有为str分配内存空间,将会发生异常
问题出在将一个字符串复制进一个字符变量指针所指地址。虽然可以正确输出结果,但因为越界进行内在读写而导致程序崩溃。
Strcpy的在库函数string.h中,程序的主要程序在于越办进行内存读写导致程序崩溃。
2.
const char* s = “AAA”;
Printf(“%s”,s);
S[0] = ‘B’;
Printf(“%s”,s);
“AAA”是字符串常量,S是指针,指向这个字符串常量,所以声明s的时候就有问题。
Const char* s =”AAA”,然后又因为是常量,所以对S[0]的赋值操作是不合法的。
Strcpy(szstr,”0123456789″);
产生什么结果?为什么?
正常输出,长度不一样,会造成非法的OS,覆盖别的内容
两种解法,一种是用算术算法,一种是用^(异或)
a = a+b;
b = a-b;
a = a-b;
or
a = a^b;//只能对int ,char
b = a^b;
a = a^b;
or
a ^= b ^=a;
char d =a;
pint(“%d”,d+1);
1
Char类型的变量赋值范围是0~255.当把256赋值给a时,超出了a的有效取值范围。此时a的实际值为0.
格式:类型标识符 &函数名(形参列表及类型说明){//函数体}
格式:在内存中不产生被返回值的副本:(注意:正是因为这点原因,所以返回一个局部变量的引用是不可取的。因为随着该局部变量生存期的结束,相应的引用也会失效。)
注意事项: