指针
指针的特点
- 指针是变量的一种,映射内存地址;
- 可以通过
&
获取变量的内存地址; - 可以通过
*
声明指针类型或者解除引用; - 指针的递增运算,不是地址值(+1),而是地址值(+指针类型大小);
- 指针指向的内存地址是按字节(byte)来划分的,一个字节为8位。所以如果两个地址相差1,实际上是相差了8位。如果是相差2,则相差了16位,以此类推;
- 空指针(void *),只占用1个地址大小,内存空间长度为0;
数组
数组的特点
- 只能在声明时被初始化;
// 正确初始化
int a[3]={1,2,3};
// 正确初始化,都被初始化为0
int a[3];
// 正确初始化,都被初始化为'\0'
char a[3];
// 错误初始化,且不能被赋值
int a[3];
a={1,2,3};
- 数组名是数组中第一个元素的地址。
为什么要强调第一个元素呢,因为类型指针不仅包含地址,还包含长度,这里数组名是第一个元素的地址,也代表长度是第一个元素的长度;
#include<iostream>
#include<stdlib.h>
using namespace std;
int main(){
int a[10];
//数组第一个元素的地址,长度为int
cout<<"a的地址:"<<a<<"\t"<<"长度:"<<sizeof(*a)<<endl;
//数组首地址,长度为(int*10)
cout<<"&a的地址:"<<&a<<"\t"<<"长度:"<<sizeof(*(&a))<<endl;
//数组首地址,长度为int
cout<<"a[0]的地址:"<<&a[0]<<"\t"<<"长度:"<<sizeof(*(&a[0]))<<endl;
return 0;
}
字符串
- c语言风格,c语言风格的字符串以’\0’结束。
char a[2]={'h','i'}; //不是字符串,而是字符数组
char a[3]={'h','i','\0'}; //是字符串
char a[]="hi"; //是字符串,引号会自动在末尾添加'\0',并且编译器会自动计算数组大小
char a="S"; //错误,这相当于把'S'和'\0'赋给a,而且是相当于把字符串“S”的首地址赋给a
char *a="S"; //是字符串,此时a是指针,指向了匿名串地址,这个匿名串会在离开作用域后被销毁。
- 如上所述,字符串是字符数组,当字符串变量
+1
时,会自增一个字符的大小:
#include<stdio.h>
int main()
{
char a[3]="abc";
*(a+1)='2';
printf("%s\n",a);
return 0;
}
- 但是通过指针定义的字符串字面值,是不能被修改的:
#include<stdio.h>
int main()
{
char *a="abc";
*(a+1)='2';
printf("%s\n",a);
return 0;
}
这种情况下,可以编译过,但运行会段错误。
为什么会这样?
因为char a[3]="abc";
是存储在栈上的变量内容,而char *a="abc";
是存储在数据段的只读内容。
注意:代码段和数据段都是只读的,堆栈段是读写的。
- 字符串字面值也是第一个字符的地址,如
char *a="abcd";
; - 因此,char数组名、char指针和引号引起来的字符串字面值,都是第一个元素的地址,也即长度为1个字符。
术语
声明:建立符号,不分配内存;
定义:绑定符号和内存地址;
初始化:相当于创建(增);
赋值:相当于修改(改);
变量:符号,映射到内存值或者内存地址,且映射内容可被更改;
指针:变量的一种,映射的是内存地址;
int型指针:一块内存空间,包含内存地址(指针)和长度(int)。
数组:一块连续的内存空间,属于容器,数组名即是首地址,数组大小即是内存空间长度。
字符串:以’\0’结尾的字符数组;
字符数组:结尾没有’\0’的字符数组;