本课主要说了C++中的变量声明,关键字register和const,同时还有一部分C++对C的加强知识。
一、C++中变量的声明和定义
1.C语言是源于操作系统的,主要注重于运行效率,而C++是C语言的加强,注重于运行效率和开发效率。
2.在C语言中,所有的变量都要求在作用域开始的时候定义,而C++可以在使用的时候再进行定义。在实际的开发中这将会提高很大的效率。
例程如下:
#include <stdio.h>
int main()
{
printf ("hello world\n");
for (int i = 3; i < 5; i++)
{
printf ("hello\n");
}
for (int i = 0; i < 2; i++)
{
printf ("world\n");
}
return 0;
}
这段代码在C++中可以正常的运行,在C环境中会报错。
这种加强是十分合理的,假如我们在写一个比较长的函数,那么每次当我们想定义变量的时候我们都要到函数的开始位置去定义变量,这样会很麻烦。
二、C++中的register关键字
1.在C语言中,register关键字是用来修饰变量的,主要作用是用来请求编译器将一个局部变量存储在寄存器中,这是C的一个优化。当然,如果我们想要去获得这个局部变量的地址是不能的(因为是寄存器地址,具体的看博客C语言中的关键字)。所以在C中,我们是不能够对一个用register修饰的变量来使用&符号的。
2.在C++中,即使是register关键修饰的变量也仍然可以使用&符号来进行操作。
其实C++中的register关键字是对C语言的一个继承,但是C++编译器大部分都有自己的优化方式,即使不使用register修饰变量也可以进行优化。
在C++中使用&符号进行操作的时候,原来的register的意义就消失了。
3.例程:
#include <stdio.h>
int main()
{
for (int i = 0; i < 5; i++)
{
register int j = 1;
printf ("%x\n", &j);
}
return 0;
}
程序在C++的环境下可以运行,运行结果如图:
疑问:老师说C++编译器可以将没有声明为register的变量放入寄存器,这里面是不是还有很多机制呢?要不然是不是会很乱?
三、C++中全局变量的定义
1.在C中可以重复定义多个同名的全局变量,但是在C++中绝对不允许的。虽然这些全局变量被定义,其实编译器只为它们开辟了一块空间,实际上最后都是链接到同一块地址空间上,也就是全局数据区。
例程:
#include <stdio.h>
int i = 1;
int i = 1;
int main(int argc, char *argv[])
{
printf ("%d", i);
printf("Press enter to continue ...");
getchar();
return 0;
}
上述程序在C环境下会报错,因为虽然我们定义了两个全局变量,但是两个全局变量并不可以都赋值(无论这两个值是否相同)。所以C语言并不是说让你可以随心所欲的定义两个值的。
上述代码最好的改进方式是:
定义一个本段程序使用的全局变量int i,同时再定义一个供外部使用的变量extern int i。不过,不论是否加extern,这两个全局变量都不可以同时赋值。
在C++中,是绝对不允许定义两个同名的全局变量的。
四、C++中的const关键字
1.C语言中的const修饰的变量不是常量,即使一个变量使用const修饰过以后我们仍然可以改变这个变量的内容,也就是说C中的const仍然是一个变量。
例程:
#include <stdio.h>
int main(int argc, char *argv[])
{
const int c = 0;
int *p = (int*)&c;
*p = 5;
printf ("%d\n", c);
}
运行结果如下所示:
这里我们首先取出const变量c的地址值赋给了p,然后再通过操作p来改变c中的值,最后我们改变了c中的值。
2.上面例子中同样的代码,在C++环境中运行的结果如下。
出现这样的打印结果原因如下:在C语言中虽然我们定义了一个变量为const类型,但是C编译器实际上还是给这个变量分配了空间,所以我们可以通过之后怎操作来改变这个地址里面的值,因为有内存空间存在嘛。在C++中,编译器不一定为const常量分配空间,分配空间的情况有两种(1)前面出现了extern (2)出现了取地址符 。我们来详细的说一下const常量在整个程序编译过程中的变化。在C编译器中,当遇见const的常量声明的时候,在符号表中放入这个常量,编译过程如果遇见这个常量则直接使用符号表中的常量进行替换,即使出现了extern或者&符号,也不会改变const的值,因为我们一直都是从符号表中取出这个变量的值的。
具体的原理图如下所示:
3.问题:不清楚符号表具体是什么,只记得学习C语言的时候一个老师提过一句。
4.通过上面的表述,我们可以发现在C++中,经过const修饰的变量彻彻底底的变为了一个常量,其功能有些类似于宏,不过两者还是有很大区别的。
例程:
在C的环境下进行编译。
# include <stdio.h>
f1()
{
#define a 3
}
f2()
{
printf ("%d", a);
}
int main(int argc, char *argv[])
{
f1();
f2();
getchar();
}
程序的运行结果为3.显然我们在函数f1()中定义的宏在函数f2()中仍然起了作用。但是如果我们换一个方法
# include <stdio.h>
f1()
{
#define a 3
const int b = 4;
}
f2()
{
printf ("%d", a);
printf ("%d", b); //这里的b将会报错,因为b是只读变量,所以不可以跨函数打印。
}
int main(int argc, char *argv[])
{
f1();
f2();
getchar();
}
这个时候在f2()函数中仍然会打印a的值,但是这里b将会报错,因为b是只读变量,不可以跨函数进行打印。
解决宏跨函数操作的方式:在宏结束的区间加上 #udef a,这样在宏结束的区间就可以解除宏的作用范围了。
虽然在C++中,const常量和宏的作用很近似,但是const常量是由编译器处理的,提供类型检查和作用域检查,但是宏是由预编译器处理的,只是进行简单的文本呢替换。
五、C++中的struct
1.C++是一门类型十分强的语言。在C语言中struct用来定义一组变量的集合。
#include <stdio.h>
typedef struct Student
{
const char* name;
int age;
}S;
int main(int argc, char *argv[])
{
S s1;
S s2;
s1.age = 123;
printf ("%d", s1.age);
return 0;
}
在C语言中,我们通常使用上述方法来进行操作,这里只是简单的对student里面的变量进行了一个封装。我们实际上是为了方便的操作一个整体。这也是结构体在C语言中的一个主要作用。
2.在C++中,strcut是一个新的类型的定义声明。也就是说我们通过strcut在程序中定义了一个新的类型。
例程:
#include <stdio.h>
struct Student
{
const char* name;
int age;
};
int main(int argc, char *argv[])
{
Student s1 = {"wangming", 20};
Student s2 = {"lidan", 30};
}
在C++中,我们可以顺利的运行这个程序,我们实际上是通过struct定义了一个student类型,然后我们通过这个类型定义了两个变量分别是s1,s2 然后就可以对这两个变量进行赋值了。但是在C语言中这种做法是完全错误的,因为我们并没有定义类型。
六、C++中的函数类型加强
1.在C语言中,其实函数的类型要求并不是十分严格,我是一个菜鸟,没有见过什么大程序,不过前阶段我在某实训机构做了一个所谓的实训项目,在做这个东西的时候,我的某一个函数始终都是没有类型的,但是程序一直都可以编译通过,直到后来我才发现这个问题。
例程:
#include <stdio.h>
fa()
{
int ret = 0;
ret = 1;
return ret;
}
fb()
{
printf ("hello world\n");
}
int main(int argc, char *argv[])
{
int b = 0;
b = fa();
printf ("b = %d\n", b);
fb(1);
return 0;
}
在上面的程序中,我们在主函数调用了两个函数fa()和fb(),我们的运行环境是C。注意:我们的两个函数都是没有函数返回值类型和参数类型的函数。但是程序的运行结果如下:
很明显,两个函数都被成功的调用了,第一个函数没有指明返回值类型但是程序还是成功的返回了整数,第二个程序我们在主函数中传递了参数,但是在调用函数中没有声明任何参数。产生这种现象的原因是C语言的默认类型导致的。很显然,C语言的函数类型和函数的参数类型以及函数的参数个数都是很宽泛的,不过我们自己在编写程序的时候最好还是注意类型,因为这样不容易出错,即使出错了也容易查找。
2.在C++中,上面的程序是编译不通的,因为C语言的默认类型方式在C++中是不合法的。
在C语言中,int f()的返回值是int类型的整数,可以接受任意类型的参数。int f(void)返回值是int类型的整数,参数为空。
在C++中,int f()的返回值是int类型的整数,没有任何参数。int f(void)和int f()具有相同的含义,返回值是int类型的整数,没有任何参数。
最后说两句题外话,最近看见了一些人感触很深,觉得干什么都要有长期学习的准备,要不然就是被淘汰。法乎上,仅得乎中。