@lishuhuakai
2015-05-19T21:27:16.000000Z
字数 5530
阅读 1386
c
c++
在C语言中,重复定义多个同名的全局变量是合法的,在C++中,不允许定义多个同名的全局变量。
C语言中多个同名的全局变量最终会被链接到全局数据区的同一个地址空间上。
下面的代码在c中完全合法:
#include <stdlib.h>
#include <stdio.h>
int g_var;
int g_var = 1;
void main()
{
printf("g_var = %d\n", g_var);
system("pasue");
}
而C++直接拒绝这种二义性的做法。
struct类型的加强:
+ C语言的struct定义了一组变量的集合,C编译器并不认为这是一种新的类型
+ C++中的struct是一个新类型的定义声明
下面的代码在c编译器下是通不过的,不过在c++编译器下确可以通过:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student
{
char name[100];
int age;
};
int main(int argc, char *argv[])
{
Student s1 = {"wang", 1};
Student s2 = {"wang2", 2};
return 0;
}
c语言中需要用typedef将Student重命名为Student才能如此大张旗鼓的使用student。
typedef struct Student
{
char name[100];
int age;
}Student;
很难想像,下面的代码居然在c编译器下面可以通过:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
f(i)
{
printf("i = %d\n", i);
}
g()
{
return 5;
}
int main(int argc, char *argv[])
{
f(10);
printf("g() = %d\n", g(1, 2, 3, 4, 5));
getchar();
return 0;
}
总结:在C语言中,
+ int f(); //表示返回值为int,接受任意参数的函数
+ int f(void);//才表示返回值为int的无参函数
在C++中,
int f()和intf(void)具有相同的意义,都表示返回值为int的无参函数
C++更加强调类型,任意的程序元素都必须显示指明类型。
下面一段代码在c编译器里通不过,不过在c++编译器里可以通过:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int a = 10;
int b = 20;
//返回一个最小数 并且给最小数赋值成3
//三目运算符是一个表达式 ,表达式不可能做左值
(a < b ? a : b )= 30;
printf("a = %d, b = %d\n", a, b);
system("pause");
return 0;
}
三目运算符在c编译器中返回的是一个变量的值。例如在上面返回的是10,对10进行赋值,自然出现错误。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int a = 10;
int b = 20;
//返回一个最小数 并且给最小数赋值成3
(a < b ? a : b )= 30;
printf("a = %d, b = %d\n", a, b);
system("pause");
return 0;
}
//结果: a = 30, b = 20
三目运算符在C++语言是返回的“变量本身”---内存空间地址。
在c语言中做些许改变就可以达到相同的效果:
void main()//改进的C语言代码
{
int a = 10;
int b = 20;
*(a < b ? &a : &b) = 30; //返回变量a的地址值,对地址值取值,可以对变量进行修改
printf("a = %d, b = %d\n", a, b);
system("pause");
}
结论:
+ C语言中的三目运算符返回的是变量值,不能作为左值使用,但是可以用作右值,如 int c = a < b ? a : b
+ C++中的三目运算符可直接返回变量本身,因此可以出现在程序的任何地方
需要注意的是:
三目运算符可能返回的值中如果有一个是常量值,则不能作为左值使用(a < b ? 1 : b ) = 30; 这句话即使在c++中也会报错。
c++添加了新的类型,bool类型。
void main()
{
int a;
bool b =true;
printf("b = %d, sizeof(b) = %d\n", b,sizeof(b));
b = 4;
a = b;
printf("a = %d, b = %d\n", a, b);
b = -4;
a = b;
printf("a = %d, b = %d\n", a, b);
a = 10;
b = a; //b还是等于1
printf("a = %d, b = %d\n", a, b);
b = 0;
printf("b = %d\n", b);
system("pause");
}
/**
结果:
b = 1, sizeof(b) = 1
a = 1, b = 1
a = 1, b = 1
a = 10, b = 1
b = 0
*/
结论:bool类型的大小是一个字节、只有0和1两个值,如果赋值不是这两者,结果还是1。
关于const一些简单的理解:
const int a = 10; //a是常量(a所代表的内存块不能被修改)
const int *p; // p所指向的内存块是不可修改的
int * const p; // p是常指针(指针变量不能被修改,但是它所指向内存空间可以被修改)
/**
我们需要这么来理解 const int *p;
int *p表示的是一个int型变量,不过该变量的地址存在p中,因此const修饰的是一个int型变量。
这和const int a其实区别不大,因为*p等价于a。
注意比较a和*p,两者都是代表变量,*p表示p是指针,p是指向变量的指针,*p代表的才是变量, 一个类似的例子是
void func(int (*p)[3]) 和 void func(int a[][3])
(*p)[3]和a[][3]所代表的东西在编译器看来都是一样的:
+ (*p)代表步长为3的一级指针,a[]代表的也是步长为3的一级指针
+ p代表的是二级指针,a代表的也是二级指针
同理我们看int * const p,const修饰的是p这个指针,因此该指针为常指针。
*/
在c中const是一个冒牌货:
int main()
{
const int a = 10;
int *p = (int*)&a;
printf("a===>%d\n", a);
*p = 11;
printf("a===>%d\n", a);
printf("Hello......\n");
return 0;
}
/**
a的值可以被修改
a===>10
a===>11
*/
C语言中const变量是只读变量,注意,是变量,有自己的存储空间。
在c++中情况大为不同:
#include <iostream>
using namespace std;
void main()
{
const int a = 10;
int *p = (int*)&a;
*p = 11;
printf("a = %d \n", a);
printf("*p = %d \n", *p);
system("pause");
}
/**
我们发现结果很令人吃惊:
a = 10
*p = 11
*/
解释:
C++编译器这么对const常量进行处理:
+ 当碰见常量声明时,在符号表中放入常量。问题:那有如何解释上面的a和*p的不同?
+ 编译过程中若发现使用常量则直接以符号表中的值替换
+ 编译过程中若发现对const使用了extern或者&操作符,则给对应的常量分配存储空间(兼容C)
联想: int &a = 1(err) & const int &a = 10(ok)?
下面一段代码,在c和c++编译器中有不同的表现:
int main()
{
const int a = 1;
const int b = 2;
int array[a + b] = {0};
int i = 0;
for(i=0; i<(a+b); i++)
{
printf("array[%d] = %d\n", i, array[i]);
}
printf("Press enter to continue ...");
getchar();
return 0;
}
/**
c中编译通不过,c++中却可以
*/
结论:C++中由const修饰的,是一个真正的常量,而不是C中变量(只读)。
总体来说,const int c = 5; ≈ #define c 5
C++中的const常量在与宏定义不同:
+ + const常量是由编译器处理的,提供类型检查和作用域检查
+ 宏定义由预处理器处理,单纯的文本替换
#include <iostream>
using namespace std;
void fun1()
{
#define a 10
const int b = 20;
//#undef a
}
void fun2()
{
printf("a = %d\n", a);
//printf("b = %d\n", b);
}
int main(int argc, char *argv[])
{
fun1();
fun2();
return 0;
}
/**
在func1中运用#define定义的a,在func2中仍然可以使用,但是用const定义的常量b在func2中却无法使用。
如何消除 #define a 10对后面的代码的影响呢?
我们可以使用#undef,她的作用是在该代码后面取消以前定义的宏定义,她的用法是 #undef + 之前已经宏定义的量,如
#define a 10
#undef a //该句后面预处理器不再用10提换a了
*/
+ 变量名实质上是一段连续存储空间的别名,是一个标号
+ 程序中通过变量来申请并命名内存空间
+ 通过变量的名字可以使用存储空间
引用是C++的概念,属于C++编译器对C的扩展。
int main()
{
int a = 0;
int &b = a; //int * const b = &a
b = 11; //*b = 11;
return 0;
}
/**
结论:请不要用C的语法考虑 b=11
*/
引用概念:
+ 在C++中新增加了引用的概念
+ 引用可以看作一个已定义变量的别名
+ 引用的语法:Type& name = var;
+ 引用做函数参数呢?(引用作为函数参数声明时不进行初始化)
#include <iostream>
using namespace std;
int main()
{
int a = 10;
int &b = a;
//b是a的别名,请问c++编译器后面做了什么工作?
b = 11;
cout<<"b--->"<< a << endl;
printf("a: %d\n", a);
printf("b: %d\n", b);
printf("&a: %d\n", &a);
printf("&b: %d\n", &b); //对同一块内存空间可以取多个别名
system("pause");
return 0;
}
/**
b--->11
a: 11
b: 11
&a: 3798852
&b: 3798852
*/
结论:1. 普通引用在声明时必须用其它的变量进行初始化
为什么必须初始化? --> 结论:很像一个只读的常量
1. 引用作为其它变量的别名而存在,因此在一些场合可以代替指针
2. 引用相对于指针来说具有更好的可读性和实用性
比较下面实现同样功能的代码:
#include <iostream>
using namespace std;
int swap(int &a, int &b)
{
int c = 0;
c = a;
a = b;
b = c;
}
int swap(int *a, int *b)
{
int c = 0;
c = *a;
*a = *b;
*b = c;
}
//引用和左值进行绑定时,将设计出高质量的程序
//引用像一个常量,能起到指针的作用
//引用和指针有关系吗?
//引用有内存空间
void main()
{
int a = 10;
int a1 = 20;
int &b = a; // type & 引用的名字 = 被引用的变量
char buf[100];
//在使用的时候,引用相当于变量的别名
b = 11; // *b = 11;
swap(a, b);
swap(&a, &b);
}
普通引用有自己的空间吗?回答是肯定的:
#include <iostream>
using namespace std;
struct Teacer {
int &a;
int &b;
};
int main()
{
printf("sizeof(Teacher) %d\n", sizeof(Teacer));
system("pause");
return 0;
}
/**
结果是:
sizeof(Teacher) 8
*/
我们可以得出结论:引用是一个有地址,引用是常量。
引用的本质:
+ 引用在C++中的内部实现是一个常指针
Type& name <--> Type* const name
+ C++编译器在编译过程中使用常指针作为引用的内部实现,因此引用所占用的空间大小与指针相同。
+ 从使用的角度,引用会让人误会其只是一个别名,没有自己的存储空间。这是C++为了实用性而做出的细节隐藏
请仔细对比间接赋值成立的三个条件:
1. 定义两个变量 (一个实参一个形参)
2. 建立关联,实参取地址传给形参: p = &a;
3. 利用*p形参去间接的修改实参的值
结论:引用在实现上,只不过是把间接赋值成立的三个条件的后两步合二为一。当实参传给形参引用的时候,只不过是c++编译器帮我们程序员手工取了一个实参地址,传给了形参引用(常量指针)。
//C语言中的变量都必须在作用域开始的位置定义!!
//C++中更强调语言的“实用性”,所有的变量都可以在需要使用时再定义。
int main()
{
int i = 0;
printf("ddd");
int k;
system("pause");
return 0;
}