数组及指针
一、数组
1、数组的概念?
1、 什么是数组?数组与普通变量有什么关系?
数组其实是集合来的,它是由多个相同类型的普通变量组合而成。当用户需要同时定义多个相同变量时,就可以使用数组。
2、 定义数组时,需要交代什么东西?
1)数组元素的个数?
2)数组中每一个元素的数据类型? ->char
short
int
long
float
double
定义公式:
数据类型 数组名字[元素的个数]
例子:定义一个具有100个int类型变量的数组
int A[100];
3、从内存空间分析数组特点:
int main()
{
int a; //在内存空间中连续申请4个字节,使用变量a间接访问这片空间。
int A[100]; //在内存空间中连续申请400个字节,使用变量A间接访问这片空间。
printf("sizeof(a) = %d\n",sizeof(a));//4
printf("sizeof(a) = %d\n",sizeof(A));//400
return 0;
}
4、定义了数组,编译器如何处理数组?
例如: int A[100]
其实分开两个部分进行处理, “int”为第二部分, "A[100]"作为第一部分。
第一部分 -> 决定内存空间中元素的个数。
第二部分 -> 决定每一个元素的数据类型
2、数组初始化
1)定义同时初始化
-> 元素数据类型 数组名字[元素个数] = {初始化列表,每一个成员之间使用","分开}
int A[3] = {100,200,300}; //编译通过
int A[3] = {100,200}; //编译通过
第三个没有赋值的成员等于0
int A[3] = {100,200,300,400}; //编译警告
警告: warning: excess elements in array initializer
int A[] = {100,200}; //编译通过 决定了下标等于2
int A[] = {100,200,300}; //编译通过 决定了下标等于3
int A[] = {100,200,300,400}; //编译通过 决定了下标等于4
2)先定义,没有初始化
int a; -> 局部变量 -> 随机值
int a; -> 全局变量 -> 0
int A[3]; -> 局部变量 -> 全部元素都是随机值
int A[3]; -> 全局变量 -> 全部元素都是0
int A[3] = {100,200}; -> 局部变量 -> 最后一个元素是0
int A[3] = {100,200}; -> 全局变量 -> 最后一个元素是0
3)先定义,后初始化 -> 一般结合循环来完成!
int A[3];
A = {100,200,300}; //编译出错
int A[3];
A[3] = {100,200,300}; //编译出错
小结论:定义数组时没有整体初始化,则之后都不能整体初始化,只能单个初始化。
int A[3];
A[0] = 100;
A[1] = 200;
A[2] = 300;
3、数组的下标
int A[3]; -> 在内存空间中连续申请12个字节,使用变量A间接访问这片内存空间,在访问数组中,使用下标来对成员进行访问。
例如:
int A[N] -> 下标范围: 0~N-1
记住: 最后一个元素是A[N-1],而不是A[N]
4、研究数组的名字含义
1)当数组名作用于sizeof()时,数组名代表这个数组的内存空间。
sizeof() -> 计算内存空间的大小
例子:
int main()
{
int A[3];
printf("%d\n",sizeof(A)); //12
}
2)当数组名不作用于sizeof()时,数组名代表数组首元素的地址。
int A[3];
数组名: A
首元素: A[0]
首元素的地址: &A[0]
结论: A = &A[0]
例子:
int main()
{
int A[3] = {100,200,300};
printf("A[0] = %d\n",A[0]);
printf("&A[0] = %p\n",&A[0]); //0xbfec8cb4
printf("A = %p\n",A); //0xbfec8cb4
return 0;
}
sizeof(粤嵌) -> 计算整个粤嵌的大小
粤嵌 -> 仅仅代表整个粤嵌第一层楼的地址
二、指针
1、指针的概念
1、什么是指针?什么是指针变量?指针干什么用?
指针 指向是内存上地址,例如: 0xbfec8cb4
指针变量指向是专门用于存放地址的变量 p
指针是唯一的地址,所以确定申请的内存空间在哪里。
例子:
int a; -> 在内存申请一片内存空间,使用变量a间接访问这片内存
&a; -> 获取a变量的地址 &-> 取址符
2、究竟&a获取到地址,存放在哪里?
指针是一个地址,地址就应该存在指针变量中。
3、指针变量如何定义?
指针变量怎样定义取决于指向的内容的数据类型。
例如: int -> int *p
char -> char *p
double -> double *p
定义步骤:
1)先写一个 *
2)在*后面写一个指针变量名 *p
3)确定指向的内容 int a;
4)把第3步的内容的变量名去掉 int
5)把第4步的结果写在第2步结果前面 int *p
结果:int *p -> 指针变量,该变量指向一个整型数据!
变量定义公式: 数据类型 + 变量名
变量名:p
数据类型: int*
例子:
int a=100; -> 在内存申请一片内存空间,使用变量a间接访问这片内存
&a; -> 获取a变量的地址 &-> 取址符
int *p = &a; -> 将a变量的地址赋值给指针变量p
4、已知指针变量的值,如何求出该地址指向的内容是什么?
取地址: 已知变量值a,求地址值。 &a
解引用: 已知地址值p,求变量值。 *p
例子:
int a = 100; -> 在内存申请一片内存空间,使用变量a间接访问这片内存
&a; -> 获取a变量的地址 &-> 取址符
int *p = &a; -> 将a变量的地址赋值给指针变量p
int b = *p; -> 解引用出p地址指向的值,再赋值给变量b
例子====
#include <stdio.h>
int main()
{
int a = 100;
int *p = &a;
printf("a = %d\n",a); //100
printf("&a = %p\n",&a); // 0xbfde90c8
printf("p = %p\n",p); // 0xbfde90c8
printf("*p = %d\n",*p); //100
return 0;
}
=======================================================
练习1: char b=‘A’ 能不能赋值给int *p ? -> 不可以,指针类型不对,只能是char *
char b = ‘A’;
char *p = &b;
printf("*p = %c\n",*p); // ‘A’
printf("*p = %d\n",*p); // 65
5、指针的内存空间多大?
指针是一个地址,在linux系统32位中,地址长度都是4字节,所有指针变量都是4字节。
sizeof(指针变量名) = 4
#include <stdio.h>
int main()
{
int a = 100;
char b = 'A';
int *pa = &a;
char *pb = &b;
printf("%d\n",sizeof(a));//4
printf("%d\n",sizeof(b));//1
printf("%d\n",sizeof(pa));//4
printf("%d\n",sizeof(pb));//4
return 0;
}
2、野指针与空指针
1、什么是野指针?
定义了一个指针变量之后,但是没有进行初始化,指针变量就会赋值一个随机值,指向一个未知区域。
int a; -> 随机值
a = 5;
int *p; -> 随机值 -> 这时候p就称之为野指针。
p = &a;
2、如何解决野指针?
1)在定义指针初始化指针指向的区域。
例子:
int a;
int *p = &a;
2)使用空指针 -> NULL
NULL其实是一个宏定义,真正NULL是等于0,被定义在一个头文件:
#if defined(__cplusplus)
#define NULL 0
#else
#define NULL ((void *)0)
#endif
例子:
int *p = NULL;
3)其实空指针只是安全区域中其中一个地址,安全区域地址范围: 0x00000000~0x08048000,只要指针指向该范围,那么指针就不会指向别的区域了。
int a;
int *p = (0x00000000~0x08048000);
p = &a;
3、如果访问了安全区域的数据,会出现什么情况?
例子:
#include <stdio.h>
int main(int argc,char *argv[])
{
int *p = (int *)0x08047000;
int a = *p;
printf("p = %p\n",p);
return 0;
}
编译: 通过
执行: 出现段错误 Segmentation fault (core dumped) -> 非法内存访问。
1、如何在程序中寻找段错误?
段错误不是语法错误,所以在编译时不会提示出错,只有等到运行时才会提示出现段错误,但是段错误不会提示在哪一行,可以通过printf()函数来寻找段错误位置,只要发生段错误,那么程序就会马上结束。
例子:
printf(“11111!\n”);
xxxx;
printf(“22222!\n”);
yyyy;
printf(“33333!\n”);
zzzz;
执行:
11111!
22222!
Segmentation fault (core dumped) -> 说明段错误是出现"yyyy;"
2、找到段错误之后,怎么处理?
一般段错误都是与指针指向有关,找到段错误准确那一行就打印对应指针的值。
4、void* 通用类型的指针?
1)void *指向一个什么类型的数据?是指向一个void型变量吗?
例子:
void a; -> 没有void型变量
void *p = &a;
void b = *p;
void *类型指针代表该指针指向任何类型,而且C语言没有void型变量。
2)把特定类型赋值给void *代表含义?
int a; --> 买了一个商场(int)
int p = &a; --> p装者商场的地址 p的数据类型是 商场(int*)
void *pa = p; --> p的地址赋值给pa,pa是void *类型,pa可以指向任何类型的数据
含义:本身p已知指向int类型,赋值给pa,pa还是指向那片区域,但是那片区域是什么类型的数据,就不知道了!
3)把void *赋值给特定类型含义?
int a; --> 买了一个商场(int)
int p = &a; --> p装者商场的地址 p的数据类型是 商场(int*)
void *pa = p; --> p的地址赋值给pa,pa是void *类型&