c语言九(3) 数组
指针
const 关键字保护数组内容
如果一个数组作为函数的形参传递,那么这个数组内容可以在被调用函数内部修改,有时候不希望这种事情发生,就需要用const来修饰,进行保护,防止修改
void func (const int array[]);
函数指针
一个函数在编译的时候会分配一个入口地址,这个入口就是函数的指针,函数名称就代表函数的入口地址.
1.指针定义方式
函数返回类型 (* 指针变量 ) (参数列表);
int (*p)();
2.函数可以通过函数指针调用
3.int (*p)()代表指向一个函数,但不是固定哪一个函数.
#include <stdio.h>
#include <stdlib.h>
void man()
{
printf("男人\n");
}
void woman()
{
printf("女病人\n");
}
int main(){
int (*p)();
int i;
scanf("%d",&i);
if(i!=0)
p=man;
else
p=woman;
p();
system("pause");
return 0;
}
在回调函数和运行期动态绑定的时候大量的用到了指向函数的指针.
2.回调函数
将函数指针作为另外一个函数的参数称为回调函数.
#include <stdio.h>
#include <stdlib.h>
int add(int x, int y)
{
return x + y;
}
int sub(int x, int y)
{
return x - y;
}
int mul(int x, int y)
{
return x * y;
}
int divi(int x, int y)
{
return x / y;
}
void func(int(*p)(int, int), int x, int y)
{
int res = p(x, y);
printf("%d\n", res);
}
int main() {
int x, y;
char temp;
int (*p1)(int x,int y);
scanf("%d%c%d", &x, &temp, &y);
printf("=");
switch (temp)
{
case '+':
func(add, x, y);
break;
case '-':
func(sub, x, y);
break;
case '*':
func(mul, x, y);
break;
case '/':
func(divi, x, y);
break;
}
system("pause");
return 0;
}
memset,,memcpy,memmove函数
(头文件: string.h)
这三个函数分别实现内存设置,内存拷贝和内存移动
使用memcpy的时候,一定要确保内存没有重叠区域。
memset函数主要用于给数组或结构体进行初始化
char str[10];
char *p=str;
memset(str,0,sizeof(str)); //这里只能写sizeof(str)(可以写数字,但不专
//业),不能用写sizeof(p);
//别想把0换成'a',我试过了,人家把
//他当ascii码97赋值了,只能数字赋值,主要还是初始化
for(int i;i<sizeof(str)/sizeof(str[0]);i++)
{
printf("%d\n",str[i]);
}
memcpy函数主要用于数组拷贝,要注意!!!内存没有重叠区域
#include <string>
char array[]="一个汉字几个字节?word和dword的区别";
char array1[34];
memcpy(array1,array,strlen(array));
//被粘贴者array1,复制了arrar,且拷贝字节为strlen(array)个
printf("%s\n",arrary1);
memmove函数主要用于移动内存块
该函数不检查源中是否有任何终止空字符--始终精确地复制数字字节
与memcpy的差别就是mememove函数处理峰内存块和目标内存块是可以重叠的
...老师不讲,百度看不懂....
通过指针访问字符串数组
char buf[100] = "hello world";
char *p = buf;
//*(p + 5) = 'a';
//p[5] = 'b';
p += 5;
*p = 'c';
p[3] = ' '; //主要是这里需要注意一下变化
printf("buf = %s\n", buf);
输出显示 buf = hellocwo ld
指针数组作为main函数的形参
int main(int argc, char *argv[]);
main函数是操作系统调用的,所以main函数的参数也是操作系统在调用时候自动填写的
argc代表命令行参数的数量
argv代表命令行的具体参数,是char *类型的
内存管理
作用域
一个C语言变量的作用域可以是代码块 作用域,函数作用域或者文件作用域。
代码块是{}之间的一段代码。
出现在{}之外的变量,就是全局变量
auto自动变量
一般情况下代码块内部定义的变量都是自动变量。当然也可以显示的使用aotu关键字
register寄存器变量
通常变量在内存当中,如果能把变量放到CPU的寄存器里面,代码执行效率会更高
register int i;
代码块作用域的静态变量
静态变量是指内存位置在程序执行期间一直不改变的变量,一个代码块内部的静态变量只能被这个代码块内部访问。
全局变量
全局变量的存储方式和静态变量相同,但可以被多个文件访问.
外部变量与extern关键字
extern int i;
全局函数和静态函数
在C语言中函数默认都是全局的,使用关键字static可以将函数声明为静态.
内存四区
栈区 堆区 静态区 代码区
代码区
代码区code,程序被操作系统加载到内存的时候,所有的可执行代码都加载到代码区,也 叫代码段,这块内存是不可以在运行期间修改的。
静态区
所有的全局变量以及程序中的静态变量都存储到静态区,比较如下两段代码的区别
int a = 0;
int main()
{
static int b = 0;
printf("%p, %p\n", &a, &b);
return 0;
}
int a = 0;
static int b = 0;
int main()
{
printf("%p, %p\n", &a, &b);
return 0;
}
栈区
栈stack是一种先进后出的内存结构,所有的自动变量,函数的形参都是由编译器自动放出栈中,当一个自动变量超出其作用域时,自动从栈中弹出。
对于自动变量,什么时候入栈,什么时候出栈,是不需要程序控制的,由C语言编译器实现
栈不会很大,一般都是以K为单位的
栈溢出
当栈空间以满,但还往栈内存压变量,这个就叫栈溢出
对于一个32位操作系统,最大管理管理4G内存,其中1G是给操作系统自己用的,剩下的3G都是给用户程序,一个用户程序理论上可以使用3G的内存空间,
堆区
堆heap和栈一样,也是一种在程序运行过程中可以随时修改的内存区域,但没有栈那样先进后出的顺序。
堆是一个大容器,它的容量要远远大于栈,但是在C语言中,堆内存空间的申请和释放需要手动通过代码来完成。
堆的分配和释放
操作系统在管理内存的时候,最小单位不是字节,而是内存页。
malloc
void * malloc(size_t _Size);
malloc函数在堆中分配参数_Size指定大小的内存,单位:字节,函数返回void *指针。
free
void free(void *p);
free负责在堆中释放malloc分配的内存。参数p为malloc返回的堆中的内存地址
calloc
void * calloc(size_t _Count, size_t _Size);
calloc与malloc类似,负责在堆中分配内存。
第一个参数是所需内存单元数量,第二个参数是每个内存单元的大小(单位:字节),calloc自动将分配的内存置0
int *p = (int *)calloc(100, sizeof(int));//分配100个int
reallor
重新分配用malloc或者calloc函数在堆中分配内存空间的大小。
void * realloc(void *p, size_t _NewSize);
第一个参数 p为之前用malloc或者calloc分配的内存地址,_NewSize为重新分配内存的大小,单位:字节。
成功返回新分配的堆内存地址,失败返回NULL.
如果参数p等于NULL,那么realloc与malloc功能一致

浙公网安备 33010602011771号