C++语言中的外部变量引用和char[],char*的若干问题探究

今天复习了一下C++的知识点,发现了一些有疑问的地方,查看了一些资料,得到一些结论,记录下来。

1,如果在一个工程目录下,存在多个头文件,这些头文件里面是否可以包含相同的变量名呢?

思考:头文件给我们的信息其实就是接口信息,我们调用一个头文件其实就是调用跟它相关的源文件,源文件一般要封装起来,因此,我们只能通过头文件调用这个api接口。

那么同一个工程下的两个头文件里面如果都包含了头文件,编译器会认为有歧义,无法判断到底调用了哪个头文件中的变量。但是在开发过程中,难免会发生这种问题。解决办法是是用名字空间namespace。C++为我们提供了名字空间,可以让我们在特定的名字空间下寻找变量。

namespace A

{

    int a = 1;

};

namespace B

{

    int a = 2;

};

通过A::a和B::a来访问两个头文件中的变量a。

值得注意的是,名字空间的名字不能相同,如果相同还是会出错,使用名字空间的好处在于只需要修改名字空间名字就可以了,不需要修改所有重名的变量。

另外,如果想使用cpp文件中的变量,需要在cpp文件中的变量之前加上extern关键字,同时,在外部调用的时候也要加上extern关键字。


2,测试了char*和char[]的几种情形:

//#define 和const变量内存分配测试
#define STRING "asdfghjkl"
const char p[] = "qwert";
const char *q = "qwert";
void test03(void)
{
//宏定义的变量会在使用的地方分配内存,调用几次分配几次内存,而const 类型的变量只分配一次内存
cout<<STRING<<endl; //第一次调用,第一次分配内存
cout<<STRING<<endl; //第二次调用,第二次分配内存

//从内存的角度分析:
//p的含义:p指向的是这个数组的首元素,但是它增长的步长为元素类型的大小,此处为1,即sizeof(char),
//&p也指向这个数组的首元素,但是它指向的是整块数组的内存,所以它增长的步长为数组的大小,此处为sizeof("qwert") = 1*6 = 6字节
//结论:p和&p相等,但是意义不同。

cout<<"**************char p[] test****************"<<endl;
cout<<"p="<<p<<endl;         //"qwert" 打印p指向的内存空间的字符串,注意直接打印p打印的是p指向内存的内容
cout<<"*p="<<*p<<endl; //"q" 打印p指向的第一个元素的值
cout<<"p+1="<<p+1<<endl; //"wert" p往后挪了移位再打印
cout<<"p[0]="<<p[0]<<endl;        //"q" 按照下标访问第一个元素
cout<<"&p[0]="<<&p[0]<<endl; //"qwert" 先取第一个元素,再取地址,[]优先级高于&
cout<<"p[1]="<<p[1]<<endl; //"w"    按照下标访问第二个元素
cout<<"&p[1]+1="<<&p[1]+1<<endl;//"ert" 先取第二个元素,再取地址,再往后挪移位

cout<<"*p+1="<<*p+1<<endl; //"q"+1 = 114 ASCII码 取第一个元素的值,再转成ASCII码再加1
cout<<"*(p+1)="<<*(p+1)<<endl; //"w"    先挪一位,再取元素的值

cout<<"&p="<<&p<<endl; //00CE7880
cout<<"&p+1="<<&p+1<<endl; //00CE7886,此处打印的为数组的地址往后加1,sizeof(p) = 6

cout<<"**************char *q test****************"<<endl;

        //指针的操作根数组相同,只有一处不同。

cout<<"q="<<q<<endl;
cout<<"*q="<<*q<<endl;
cout<<"q+1="<<q+1<<endl;
cout<<"&q[0]="<<&q[0]<<endl;
cout<<"q[1]="<<q[1]<<endl;
cout<<"&q[1]+1="<<&q[1]+1<<endl;

cout<<"*q+1="<<*q+1<<endl;
cout<<"*(q+1)="<<*(q+1)<<endl;

cout<<"&q="<<&q<<endl; //00CE9040
cout<<"&q+1="<<&q+1<<endl; //00CE9044,不同了。此处打印的为指针的地址往后加1,sizeof(q) = 4

}

分析:char[]和char*最大的区别在于char[]分配了内存,而char*没有分配内存。

例如

char p[] = "1234567";

char*q = "1234567";

在编译阶段,p就分配了内存,而在运行阶段,将全局区的字符串“1234567”的地址赋给q。

因此,sizeof(p) = 8,sizeof(q) = 4.

另外,通过将数组首地址付给指针,又发现了新的问题:

char p[] = "1234567"; //编译阶段就分配了内存
cout<<&p<<endl;
char *m = &p[0];    //现在m指向p的首地址了
cout<<m<<endl;    //“1234567”

char *s = p;    //s也指向p的首地址了,注意,p是个地址,其实这里s指向字符p[0],即s为&p[0]

cout<<s<<endl;    //"1234567"

打印出的是s指向的内存的内容

那我如果想要通过指针m来打印指向的内存的地址,该怎么办呢?根同学讨论了一下,哦,原来打印出来的结果跟类型相关。什么意思?就是打印出来的值跟原来的类型是一样的,这里打印出s就是char*,不就是字符串嘛,要是打印地址才怪了,又不是指向字符!因此如果想要打印出地址,就得控制打印的类型,由于地址在内存中是十六进制的方式,因此控制输出为16进制即可输出指针指向的数组的地址了!

cout<<hex<<int(m)<<endl;

cout<<hex<<int(s)<<endl;


另外,之前还犯了一个错误,就是

char l[] = "123";

char *k = &l;

我想通过k得到字符数组l的地址,结果给我报错。一分析,原来还是之前那个问题,想用char*类型的指针得到地址,只能是字符!可是现在l的地址指向的是一个字符数组,怎么可能给你?怎么办?强转!

char *k = (char *)&l;    //这里将数组的首地址强制转换为数组第一个元素的地址!两个地址是相同的

如此以来k就指向了l[0],即k=&l[0]。其实跟之前那个m是一个道理,然后输出的内容跟前面一样了。

另外,之所以cout<<k<<endl;能够输出“123”首先是采用默认的char*字符串格式,另外,又因为数组是连续存放的,在碰到\0之前它不会停止。

今天就这样了。

猜你喜欢

转载自blog.csdn.net/u012260341/article/details/79586773