C-数组, 字符串的输入输出, 内存分配, 三种内存分配函数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C-数组, 字符串的输入输出, 内存分配, 三种内存分配函数相关的知识,希望对你有一定的参考价值。


数组初始化

1.数组初始化的时候, 可以这样
1 int len = 3;
2 int arr[len];
2.但是这样不可以:
1 int len = 3;
2 int arr[len] = {1, 2, 3};
3.但是可以这样:
1 int arr[3] = {1, 2, 3};
2不可以的原因:
编译器编译的时候 int arr[3] = {1, 2, 3}这种方式会转换成:
1 int arr[3];
2 arr[0] = 1;
3 arr[1] = 2;
4 arr[2] = 3;
而2的方式在编译的时候, 无法确定数组的长度:因为变量只有在执行的时候才会得到其值, 所以直接就会报错, 但是用宏没问题
 
数组初始化的方法补:
指定下标初始化
1 int arr[10] = {[1] = 1, [2] = 2, [3] = 0};
剩余未进行赋值的自动赋0
 
如何将数组的所有元素初始化为0:
1 int arr[10] = {0};
 

数组命名规范(建议):

由于数组一般是存储多个数据
所以在命名的时候, 最好是名词的复数形式(如果是英文名词的话)
 

数组地址辨析:

int arr[10]
首地址:
1. arr[0]
2. arr
数组的地址 == 数组名 == arr[0] == arr[0]的首地址 == 数组中低字节的地址(存的时候是低位存储)
所以:我们不能直接打印数组名, 这样得不到数组的元素的值, 因为数组名代表的其实是数组的地址, 所以打印数组名的时候用%p
 

数组的长度计算

1.数组的每一个元素的类型相同, 所以数组的每一个元素占用的空间一样
2.使用sizeof运算符 可以计算 数组总共占用的字节数
 
注意: 当数组作为函数的参数的时候, 那么在传递的时候, 会丢失数组的长度.
当数组作为函数的参数的时候, 在函数的内部使用sizeof计算参数数组长度, 得到的永远都是8
原因: 并不会真正的去声明一个新的数组, 而是声明了一个同名指针然后指向了原有数组, 一个指针8个字节  所以就是8了
当数组作为函数的参数的时候, 并不是一个数组, 而是一个指向实参数组首地址的指针
所以传值的时候, 其实是通过形参指针在操作实参数组——地址传递. 数组特有
 
 

字符串的输入输出

gets()不安全的原因
不会自动加 ‘\0‘结束符
假设一个char类型的数组长度为50
get()的话会把所有的输入都存在这个数组中
从而导致越界访问
 
升级版—— fgets(字符数组名, 数组长度, 输入源);
假设数组char ch[5];
那么fgets(ch, sizeof(ch), stdin)
只会将输入的前4个字符存入数组中,并在最后一个加上\0
如果输入的字符串长度小于数组长度的时候,函数还会接收回车
输入源可以是文件,键盘输入
 
fputs(): 字符串输出函数
1.不会自动换行
2.没有格式控制
这两个函数的优点: 能够自动截取长度
 
最主要的还是写入和读取字符串到文件
 
 

const

1.const修饰的指针变量指向可变,指向的变量的值不能改变
1 const int *p = &a;
2 p = &b;
3 int const *p1 = &a;
4 p1 = p;
 
2.const修饰的指针变量,指针变量指向的变量值可以变,指向不能变
1  int *const p2 = &a;
2 *p2 = 2000;
 
3.const修饰的指针变量的指向和值,都不能改变
1 const int * const p3 = &a;
2 p3 = &a;  //不可以
3 *p = 100; //也不可以
 
以上3种情况辨析
如果 const 在 * 的左侧   表示指针变量指向的变量的值不能变,但是指向可以改变
如果 const 在 * 的右侧   表示指针变量指向的变量的值可以改变,但是指向不能改变
如果 * 的左右两侧都有const  表示指针变量指向的值和指针变量的指向都不能变
 
const的最大优点:
提高了效率.   编译器通常不为普通的const常量分配存储空间, 二是将它们保存在符号表中, 这使得它成为一个编译期间的常量, 没有了存储与读内存的操作, 使得它的效率也很高
 
使用const:
修饰一般常量  一般常量是指简单类型的常量.  这种常量在定义是, 修饰符const可以用在类型说明符前, 也可以用在类型说明符后
 
使用场合:
1. 修饰变量
2. 修饰指针变量
3. 修饰数组
 

计算机内存分配

1. 静态存储区分配: 在程序编译的时候就已经分配好了,这块内存在程序的整个运行期间都存在,全局变量,static变量
 
2.栈上分配
 
3.堆上分配: 动态分配: 程序在运行的时候用malloc或new申请的内存   用free和delete的释放内存技术分享
内存5大分区
BBS段: bss segment, Block Started by Symbol 的简称, 通常是指用来存放程序中未初始化的全局变量和静态变量
 
数据段: 存放程序中的已初始化的全局变量和静态变量,静态内存分配,  字符串常量
 
代码段: 程序执行代码的一块内存区域  执行后的存放地方
 
堆区: 动态非配的内存段   大小不固定
 
栈区: 堆栈, 用户存放程序临时创建的局部变量  first in first out  
 

常用内存分配函数:

内存申请
malloc(需要申请的内存的长度)  malloc(4*sizeof(int))
从内存的堆区分配大小为size个字节的连续的内存空间, 如果内存分配成功, 返回的新空间的首地址, 如果失败, 返回null
所以一般使用的时候,最好加个判断, 是否分配成功
 
calloc(a, b)    分配a块长度为b的内存空间
calloc(4, sizeof(int))
两个函数分配的内存空间的地址都是连续的
所以一般使用的时候,最好加个判断, 是否分配成功
calloc相较于malloc的优势: calloc申请完后, 就会自动将字节清零(初始化)
 
内存扩展
realloc() 函数: 可以给已经存在的空间扩充(不严谨)大小
1.先检测, 已分配好的内存空间紧邻的内存空间是否还有蛮满足条件的连续的内存空间
有:直接申请后面的这一块连续的内存空间
没有: 在内存的其他位置 找其他满足条件的,连续的内存空间, 然后把已有的内容直接拷贝到新申请的空间中
申请:
int *p = (int *)malloc(4*sizeof(int));
扩充(或者重新分配)
realloc(p, 40*sizeof(int));
返回的是: 新空间的地址(如果是重新申请的话)
 

野指针管理

定义指针变量的同时最好初始化, 如果有对应的赋值就赋值, 如果没有赋值就初始化为NULL, 用完指针之后也将指针变量的值设置为NULL 

以上是关于C-数组, 字符串的输入输出, 内存分配, 三种内存分配函数的主要内容,如果未能解决你的问题,请参考以下文章

通过动态分配创建数组后,在C中通过realloc改变内存大小时出现问题

c语言 动态数组

c++中用new给未知大小的数组分配空间怎么弄?

go:内存分配

重新分配内存并在C中重新分配的内存空间添加一个字符串

c关于数组所占内存大小问题