数组
数组用来存放多份数据,但是它有两个要求:
1.这些数据的类型必须相同;
2.这些数据在内存中必须连续存储。
如果没有数组,存储多份数据就需要多个变量名,管理和使用起来都非常麻烦;而有了数组,只需要一个变量名就能搞定。
来看个简单的例子:
int nums[4]; //定义了一个存储4个整数的数组
float temp[100]; //定义一个可以存储 100 个浮点数的数组
char name[20]; //定义一个可以存储 20 个字符的数组
数组的初始化
上面的代码是定义数组,我们也可以在定义数组的同时赋值,这叫做初始化。
例如:
int nums[5] = {10, 20, 30, 40, 50};
//数组元素的值由{ }包围,各个值之间以,分隔。
值的类型要和数组的类型匹配,当然如果匹配不上,会自动转换类匹配。
数组的内存分布:
数组在内存中一定是连续存放的
比如:

sizeof()运算符
sizeof()是一种编译时运算符提供了存储操作数的类型的对象所需的存储空间量(以字节为单位).
sizeof 数组名 得到的结果是整个数组的长度(单位为字节)
如果想要计算数组单个元素的长度,就使用 sizeof 数组名[下标] 的方式
如果想要得到数组元素的个数,只需要将上面两种计算公式结合起来.
即sizeof(array) / sizeof(array[0])
字符数组与字符串
字符数组是专门用来存储字符数据的数组,其每个元素存放一个字符,定义形式与一般数组类似,但元素类型为char
char names[] = {'s','a','n'};
字符串
在 C 语言中,字符串实际上是使用空字符 \0 结尾的一维字符数组。因此,\0 是用于标记字符串的结束。
比如上面的字符数组就可以用字符串来表示
char* name = "san"; //默认都是\0结尾
char name[] = "san" //默认都是\0结尾
但两种有本质的不同:
char* name = "zhangsan"这里 name 是一个指向字符串常量的指针。字符串常量通常存储在只读内存区域(如数据段或文本段),修改它会导致未定义行为。
| 对于第二种其实里面有许多细节值得我们研究 |
char name[] = "zhangsan"; 这里 name 是一个字符数组,数组元素存储在栈上(或静态存储区,取决于作用域)并且这种其实是发生了字符拷贝
具体如下:
char arr[] = "san";
// 实际上相当于:
char arr[4]; // 1. 在栈上分配4字节
arr[0] = 's'; // 2. 逐个字符拷贝
arr[1] = 'a';
arr[2] = 'n';
arr[3] = '\0';
char names[] = {'s','a','n'};但是对于这种情况,数组name里面就只有三个字符,没有多的 \0,明面上存的什么就是什么,不会有多的 \0 ;
并且对于arr来说本质上是一个数组,但在大多数表达式中会退化为指针 !
#include <stdio.h>
int main()
{
char arr[] = "san";
// 情况1:仍然是数组(不退化为指针)
printf("sizeof(arr) = %u\n", sizeof(arr)); // 输出:4(数组大小)
printf("&arr = %p\n", &arr); // 取整个数组的地址
printf("&arr + 1 = %p\n", &arr + 1); // 跳过整个数组
// 情况2:退化为指针(大多数情况)
printf("arr = %p\n", arr); // 退化为 char*(首元素地址)
printf("arr + 1 = %p\n", arr + 1); // 指向第二个元素
printf("*arr = %c\n", *arr); // 可以解引用
printf("arr[1] = %c\n", arr[1]); // 数组下标访问
printf("%s\n", arr); 传递给函数时也退化为指针
return 0;
}
区分表:

记住:数组名不是指针,但可以像指针一样使用(因为编译器会自动转换)!
还有一种情况特别说明:
char str5[5] = "hello";

内存分布如图:
指针
指针的概念:
&a 就是a的地址(编号) , 实质上也可以理解为他是一个 指向 a数据的存放的内存区域地址编号。
我们可以定义一个指针,把这个地址赋值给它,那么我们定义指针的值那个地址编号。指向的就是那个变量的值的资质。一个地址编号是恒定的由系统确定,不会应该数据类型不一样而改变。
#include <stdio.h>
int main(int argc, char const *argv[])
{
int a = 1;
//&a//a变量所对应数据的地址
int *ap = &a; //申明指针并初始化
float f = 1;
float *fp = &f; //申明指针并初始化
double d;
double * dp; //申明指针没有初始化
dp = &d ; //初始化
return 0;
}
两种特殊指针
野指针
概念: 指向一块未知内存的指针, 被称为野指针。
int * p ;
- 危害:引用野指针的时候,很大概率我们会访问到一个非法内存,通常会出现段错
误(Segmentation fault (core dumped))并导致程序崩溃。
更加严重的后果,如果访问的时系统关键的数据,则有可能造成系统崩溃
-
产生原因:
定义时没有对他进行初始化
指向的内存被释放,系统已经回收, 后该指针并没有重新初始化
指针越界
- 如何防止:
定义时记得对他进行初始化
绝对不去访问被回收的内存地址, 当我们释放之后应该重新初始化该指针。确认所申请的内存的大小,谨防越界
空指针:
在很多的情况下我们一开始还不确定一个指针需要指向哪里,因此可以让该指针先指向
一个不会破坏系统关键数据的位置, 而这个位置一般就是NULL (空)。因此指向该地址
的指针都称之为空指针

1259



被折叠的 条评论
为什么被折叠?



