1、使用cout输出一个字符串,或者用strlen获取一个字符串的长度,都是找到该地址开始后面的第一个’\0’为止,对于普通的字符数组,甚至其他类型的数组,是不能使用该方法进行操作的。总之,如果给cout提供一个字符的地址,则它将从该字符开始打印,直到遇到空字符为止。
2、一定要在对指针使用解除引用运算符(*)之前,将指针初始化为一个确定的、适当的地址。
int * fellow;
*fellow = 233;//将233放到一个未知的地方
3、使用delete的关键在于,将它用于new分配的内存,即用于new的地址,而不是new的指针本身。
int * ps = new int;
int * pq = ps;
delete pq;//使用第二个指针来释放该内存,不能重复释放,如再次调用delete ps。
4、不能使用sizeof运算符来确定动态分配的数组包含的字节数。
int *a = newint[3];
cout <<sizeof(a) << endl; //输出4,即地址的字节数
在参数传递的时候也是如此,为了将数组类型和数组长度告诉处理函数,应使用如下形式:
void fillArray(int arr[], int size);
不能在函数中使用sizeof arr的原因:指针本身并没有指出数组的长度。
5、使用new创建动态数组,要用delete[]来释放,注意,修改指针位置后,释放前要将指针返回原来的位置。
int *nums = new int[3];
nums[0] = 0;
nums[1] = 1;
nums[2] = 2;
nums = nums + 1;
delete [] nums;//无效
int*nums1 = nums - 1;
delete [] nums1;
6、将指针变量加1后,其增加的值等于指向的类型占用的字节数。
注:数组的地址
还可以将一个指针减去另一个指针,获得两个指针的差,仅当两个指针指向同一个数组时,得到两个元素的间隔。
7、在很多情况下,可以使用相同方式使用指针和数组名。区别之一是,可以修改指针的值,而数组名是常量。另一个区别是,对数组应用sizeof运算符得到的是数组的长度,而对指针应用sizeof得到的是指针的长度,即使指针指向的是一个数组。
8、在将字符串读入程序时,应使用已分配的内存地址。该地址可以是数组名,也可以是使用new初始化过的指针。
1、在for循环中,对于内置类型,采用++i与i++不会有差别,但对于用户定义的类型,如果有用户定义的递增和递减运算符,则前缀格式的效率更高。因为用户这样定义前缀函数:将值加1,然后返回结果;但后缀版本首先复制一个副本,将其加1,然后将复制的副本返回。
2、string类重载了==和!=运算符,条件是,至少有一个操作数为string对象,另一个操作数可以使string对象,也可以是C-风格字符串(一个以’\0’结尾的字符数组或者””括起来的字符串常量)。而两个C-风格字符串不能直接使用==或者!=。
3、C++中为类型创建别名有两种方法:
1)使用#define,如:
#define BYTE char//BYTE成为char的别名
2)使用typedef
typedef char byte;
就像用char声明一个变量一样,只是在前面加上typedef关键字。
不过,声明一系列变量时,不能用#define,如
#define FLOAT_POINTER float *;
fLOAT_POINTER pa,pb;
编译器会该声明转换为:
float * pa,pb;
这样,pb并不是指针,而是值。使用typedef则不会有这样的问题。
1、
2、读取文件是,good()方法指出最后一次读取输入的操作是否成功,这一点至关重要。这意味着应该在读取输入后立刻执行这种检测。为此,一种标准的方法是,在循环之前(首次执行循环测试前)放置一条输入语句,并在循环的末尾(下次执行循环测试之前)放置另一条输入语句。
//standard file-reading loop design
inFile >> value; //get first value
while(inFile.good()) //while input good and not at EOF
{
//loopbody
inFile>> value; //get next value
}
或者,
while(inFile >> value)
{
//loopbody
}
1、除非函数的目的就是修改传递给它的数据,否则应该避免发生这种情况。使用普通参数时,这种保护将自动实现,这是由于C++按值传递数据,而且函数使用数据的副本。然而,接受数组名的函数将使用原始数据,为防止无意中修改数据的内容,可以在声明形参时使用const关键字。
2、如果数据类型本身不是指针,则可以将const数据和非const数据的地址赋给指向const的指针,但只能将非const数据的地址赋给非指向const的指针。
3、指向const的指针和const指针
1)指向const的指针表示的是指针指向的值(可以是无const修饰的普通变量)不能通过”*指针”的方式修改
int sloth = 3;
const int * ps = &sloth;
此时,不能使用*ps += 1或 cin >> *pt的方式来修改值,不过可以通过sloth本身来修改。
但是ps指针本身是可以被修改的
int number = 4;
ps = &number;
2)const指针
无法修改指针的值
int * const finger = &sloth;
此时,finger只能指向sloth,但允许使用finger来修改sloth的值。
1、const只能修饰指向基本类型的指针,不能修饰指针的指针。
1、必须在声明引用变量时进行初始化。简而言之,可以通过初始化声明来设置引用,但不能通过赋值来设置。
引用更接近const指针,必须在创建的时候进行初始化,一旦与某个变量关联起来,就将一直效忠于它。也就是说:
int& rodents = rats;
实际上是下述代码的伪装表示:
intconst *pr = &rats;
2、如果函数调用的参数不是左值(不是左值例如字面值)或与相应的const引用参数的类型不匹配,则C++将创建类型正确的匿名变量,将函数调用的参数的值传递给匿名变量,并让参数来引用该变量。
如果接受引用参数的函数的意图是修改作为参数传递的变量,则创建临时变量将阻止这种意图的实现。解决方法是,禁止创建临时变量,现在C++标准正是这样的。
3、将引用参数声明为常量数据的引用的理由有三个:
1)使用const可以避免无意中修改数据的编程错误;
2)使用const使函数能够处理const和非const实参,否则将只能接受非const数据;
3)使用const引用使函数能够正确生成并使用临时变量。
因此,应尽量将引用声明为const。
4、返回引用时最重要的一点是,应避免返回函数终止时不再存在的内存单元引用。应避免编写下面的代码:
const free_throws & clone2(free_throws& ft)
{
free_throwsnewguy;
newguy= ft;
returnnewguy;
}
该函数返回一个指向临时变量(newguy)的引用,函数运行完毕后它将不复存在。同样,也应该避免返回指向临时变量的指针。
为避免这个问题,最简单的方法是,返回一个作为参数传递给函数的引用。
另一种方法是用new来分配新的存储空间。
const free_throws & clone(free_throws& ft)
{
free_throws*pt;
*pt= ft;
return*pt;
}
这种方法存在一个问题:在不再需要new分配的内存时,应使用delete来释放,容易被遗忘。
1.默认参数的使用:
char * left(const char * str, int n = 1);
2.参数传递的指导原则:
对于使用传递的值而不做修改的函数:
1)如果数据对象很小,如内置数据类型或小型结构,则按值传递。
2)如果数据对象是数组,则使用指针,因为这是唯一的选择,并将指针声明为const的指针。
3)如果数据对象是较大的结构,则使用指针或者引用,提高程序运行效率。这样可以节省复制结构所需的时间和空间。
4)如果数据对象是类对象,则使用const引用,类设计的语义常常要求使用引用。、
对于修改调用函数中数据的函数:
1)如果数据对象是内置数据类型,则使用指针。
2)如果数据对象是数组,则只能使用指针。
3)如果数据对象是结构,则使用指针或引用。
4)如果数据对象是类对象,则使用引用。
1.头文件中应该包含的内容
2.
3.外部变量的使用
C++提供了两种变量声明。一种是定义声明,或简称定义,它给变量分配存储空间;一种是引用声明,或简称声明,它不给变量分配存储空间,因为它引用已有的变量。
引用声明使用extern,且不进行初始化。如果要在多个文件中使用外部变量,只需要在一个文件中包含该变量的定义,但在使用该变量的其他所有文件中,都必须使用关键字extern声明它。
4.局部静态变量的使用
如果在函数中声明了局部静态变量,则多次调用该函数时,访问的是同一个变量,程序开始运行时初始化一次,以后便一直存在。
#include <iostream> using namespace std; const int ArSize = 10; void strcount(const char* str); int main() { char input[ArSize]; char next; cout << "Enter a line:\n"; cin.get(input,ArSize); while(cin) { cin.get(next); while(next != '\n') { cin.get(next); } strcount(input); cout << "Enter next line (empty line to quit):\n"; cin.get(input,ArSize); } cout << "Bye.\n"; return 0; } void strcount(const char* str) { static int total = 0;//局部静态变量 int count = 0; cout << "\"" << str << "\" contains "; while(*str++) { count ++; } total += count; cout << count << " characters \n"; cout << total << " characters total\n"; }
其中total为局部静态变量,可以计算多次调用该函数时,总的次数。
2.C++对结构进行了扩展,使之具有与类相同的特性。他们之间唯一的区别是,结构的默认访问权限是public,而类为private。
3.所创建的每个新对象都有自己的存储空间,用于存储其内部变量和类成员;但同一个类的所有对象共享同一组类方法,即每种方法只有一个副本。
4.不要将类成员名称用作构造函数的参数名,为避免混乱,通常在数据成员中使用m_前缀或者后缀_。
5.C++提供了两种使用构造函数的方法。
第一种是显示地调用构造函数:Stock food = Stock("aaa",250,1,25);
另一种方式是隐式地调用构造函数:Stock garment("bbb",123,1.22);
将构造函数与new一起使用的方法:Stock *pstock = new Stock("ccc",142,1.34);此时创建了一个Stock对象,对象没有名字,但是可以用pstock指针来管理该对象。
6.默认构造函数是在未提供显示初始值时,用来创建对象的构造函数。也就是说,它是用于下面这种声明的构造函数:Stock stock;
在设计类时,通常应提供对所有类成员做隐式初始化的默认构造函数。隐式的调用默认构造函数时,不要使用圆括号。
7.只要类方法不修改调用对象,就应该将其声明为const。
声明时:void show() const;
定义时:void Stock::show() const
8.接受一个参数的构造函数允许使用赋值语句将对象初始化为一个值。即如果构造函数只有一个参数,则将对象初始化为一个与参数类型相同的值时,该构造函数将被调用。
9.如果构造函数使用了new,则必须提供使用delete的析构函数。
10.this指针指向用来调用成员函数的对象(this被作为隐式参数发送给对象)。一般来说,所有的类方法都将this指针设置为调用它的对象的地址。如果方法需要引用这个调用对象,则可以使用*this。在函数的括号后面使用const限定符将this指针限定为const,这样,不能使用this来修改对象的值。