广州网站建设 信科公司/百度指数数据
指针:
含义:是一个值,一个值代表着一个内存地址,类似于存放路径
* 运算符 :
1 字符*
表示指针
作用:通常跟在类型关键字的后面,表示指针指向的是什么类型的值
int * foo, * bar;声明指针后会随机分配一个内存空间,指针指向的数据是随机的指针的初始化:
int* p;
int i;p = &i;
*p = 13;未初始化的指针数据最好这样定义:int* p = NULL;
2 运算符
作用:用来取出指针变量所指向的内存地址里面的值
* foo 取出定义的指针的值/*注意,数组名指向的地址是不能更改的*/
& 运算符:
作用:用来取出一个变量所在的内存地址int i = 5;if (i == *(&i)) // 正确,*(&i)含义:先取出i的内存地址,在获取内存地址对应的值
运算:
1 指针与整数值的加减运算
指针与整数值的运算,表示指针的移动。
2 指针与指针的加法运算
两个指针进行加法是非法的
3 指针与指针的减法
相同类型的指针允许进行减法运算,返回它们之间的距离,即相隔多少个数据单位。
高位地址减去低位地址,返回的是正值;低位地址减去高位地址,返回的是负值
返回值:ptrdiff_t
类型,一个带符号的整数类型别名
4 指针与指针的比较运算
比较的是各自的内存地址哪一个更大,返回值是整数1
(true)或0
(false)
函数:
基础结构:
#include <stdio.h>/* 基础结构*/int main(void)
{int m = addNum(3); /* 使用函数, 3 传递的参数*/printf("m=%d", m);
}int addNum(int a) /* int addNum 定义函数名称 (int a 传递参数,可以传递多个,使用逗号分开) */
{ /*{函数体:使用此方法需要执行的语句}*/return a; /* return a; return 返回值,返回计算之后的数据 */
}
参数:
传递的参数是拷贝的数据,非自身数据,不会实时更新数据;
除非1 函数返回最新的数据,才可以获取并赋值最新的数据2 直接修改自身的署,传入变量的地址(函数不要返回内部变量的指针)void Swap(int* x, int* y) {int temp;temp = *x;*x = *y;*y = temp;
}int a = 1;
int b = 2;
Swap(&a, &b);//参数为数组
int sum_array(int a[n], int n) {// ...
}int sum = sum_array(a, 4);
//等同于
int sum = sum_array((int []){3, 5, 7, 3}, 4);/*多维数组*/
int sum_array(int n, int m, int a[n][m]);
参数数量是不确定时,声明函数的时候,可以使用省略号...
表示可变数量的参数
注意:...
符号必须放在参数序列的结尾,否则会报错
#include<stdio.h> #include<stdarg.h> /* 可以操作可变参数的类*/double average(int i, ...);double average(int i, ...) {double total = 0;va_list ap; /*va_list 一个数据类型,用来定义一个可变参数对象*//* va_start(ap, i); 将参数i后面的参数统一放入ap*/va_start(ap, i); /*va_start 一个函数,用来初始化可变参数对象 va_start(可变参数对象,正常参数,用来为可变参数定位)*/printf("i=%d \n", i);for (int j = 1; j <= i; ++j) {/* va_arg(ap, double)用来从ap依次取出一个参数,并且指定该参数为 double 类型*/total += va_arg(ap, double); /* va_arg 一个函数,用来取出当前那个可变参数 va_arg(可变参数对象,当前可变参数的类型)*/printf("total=%d \n", total);}printf("ap=%d \n", ap);va_end(ap); /* va_end 一个函数,用来清理可变参数对象*/return total / i;
}int main(void)
{int total=average(0,8,10);printf("total=%d", total);
}
递归函数:
函数可以调用自身,这就叫做递归(recursion)例如:
#include <stdio.h>int main(void)
{int m = addNum(3);printf("m=%d", m);
}int addNum(int a)
{a++ ;if (a <= 5){addNum(a);}else{return a;}
}注意:在使用递归函数时,注意做好判断,不然容易出现死循环
入口函数:
main()是程序的入口函数,所有的程序必须要有
类似于页面加载方法,首先执行此方法
其他的方法需要通过main调用#include <stdio.h>int main(void)
{int m =3;printf("m=%d", m);return 0; /* 表示函数结束运行,返回0; 返回非零数据表示运行失败*/
}
函数指针:
调用函数的方法
// 写法一 常用的 函数名本身就是指向函数代码的指针,通过函数名就能获取函数地址
print(10)// 写法二
(*print)(10)// 写法三
(&print)(10)// 写法四
(*print_ptr)(10)// 写法五
print_ptr(10)#include<stdio.h> int addNum(int a)
{return a;
}int main(void) /*调用其他方法时,其他方法要么写在最前面, 或者使用函数原型*/
{// int m = addNum(3);// printf("m=%d", m);int m = (*addNum)(10);printf("m=%d", m);
}优点:
可以明确参数是一个函数参数一就是一个函数
int compute(int (*myfunc)(int), int, int);
函数原型:提前告诉编译器,每个函数的返回类型和参数类型int twice(int);int main(int num) {return twice(num);
}int twice(int num) {return 2 * num;
}注意,函数原型必须以分号结尾。一般来说,每个源码文件的头部,都会给出当前脚本使用的所有函数的原型。
exit函数:
作用:终止程序的运行
前提: #include<stdlib.h>
返回值(stdlib.h已定义,无需定义):EXIT_SUCCESS(相当于 0)表示程序运行成功EXIT_FAILURE(相当于 1)表示程序异常中止
atexit()函数:用来登记exit()执行时额外执行的函数,用来做一些退出程序时的收尾工作
说明符:
extern 说明符 :
extern int foo(int arg1, char arg2);
extern 表示:导入使用,声明此方法未在此文件定义,是从其他文件内引入使用的int main(void) {int a = foo(2, 3);// ...return 0;
}
static 说明符:
1 用于函数内部声明变量时,表示该变量只需要初始化一次,不需要在每次调用时都进行初始化
2 static
可以用来修饰函数本身,表示该函数只能在当前文件里使用,如果没有这个关键字,其他文件也可以使用这个函数(通过声明函数原型)
3 用在参数里面,修饰参数数组
int sum_array(int a[static 3], int n) { /* 数组长度至少为3*/}
注意:
static
修饰的变量初始化时,只能赋值为常量,不能赋值为变量
局部作用域中,static
声明的变量有默认值0
const 说明符:
1 函数内部不得修改该参数变量
void f(const int* p) {int x = 13;p = &x; // p本身的地址是允许修改的*p = 0; //const声明的* p 不能修改,修改之后报错
}
void f(int* const p) { //不允许修改p,就使用const定义int x = 13;p = &x; // 该行报错
}/* p和*p 都不允许修改 */
void f(const int* const p) {
}
内存管理:
分类:
系统管理:局部变量存放的内存区域(”栈“(stack)),运行结束后自动从内存卸载
用户手动管理:全局变量存放的内存区域(”堆“(heap)),运行结束后不会自动卸载,需要用户手动释放,此现象叫”内存泄漏“(memory leak)
void 指针:
void:不定类型的指针可以指向任意类型的数据,但是不能解读数据void 指针与其他所有类型指针之间是互相转换关系
注意,由于不知道 void 指针指向什么类型的值,所以不能用*运算符取出它指向的值
内存操作:
分配内存:
malloc:
#include <stdio.h>
#include <stdlib.h> /*内存管理的操作*/int main(){/* malloc(分配的内存字节数--非负整数) 任意类型的数据分配内存 返回值:无类型的 void 指针*///malloc不会对所分配的内存进行初始化,需要自行初始化后再使用,想要初始化为0,还要额外调用memset()函数int* p = malloc(sizeof(int));*p = 12;if (p == NULL) {// 内存分配失败}printf("%d\n", *p); int* n = (int*) malloc(sizeof(int)); //强制转换数据为整数类型printf("n=%d\n",*n);int* i = (int*) malloc(sizeof(*i));printf("i=%d\n",*i);//作用://1 为数组和自定义数据结构分配内存int* t = (int*) malloc(sizeof(int) * 10);for (int i = 0; i < 10; i++)t[i] = i * 5;printf("t==%d",t);//2 创建动态数组int m;int* a = (int*) malloc(m * sizeof(int)); //可以根据变量m的不同,动态为数组分配不同的大小}
calloc:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main(){// calloc(数据类型的值的数量,数据类型的单位字节长度) 分配内存, 返回值:无类型的 void 指针,分配失败时,返回 NULL//calloc所分配的内存全部初始化为0int* p = calloc(10, sizeof(int));printf("p==%d, %d \n",p,*p);// 等同于int* n = malloc(sizeof(int) * 10);memset(n, 0, sizeof(int) * 10);printf("n==%d, %d \n",n,*n);
}
释放内存:
free:
#include <stdio.h>
#include <stdlib.h>int main(){//free(malloc返回的内存地址) 释放malloc函数分配的内存//分配的地址释放之后,不可操作和再次释放// 注意:函数调用成功后,一定要释放内存,否则会导致多次调用函数所生成的内存下次无法访问int* p = (int*) malloc(sizeof(int));*p = 12;printf("address=%d",p);free(p);
}
修改内存:
realloc:
#include <stdio.h>
#include <stdlib.h>int main(){//realloc(已经分配好的内存块指针,内存块的新大小,单位为字节) 修改已经分配的内存块的大小,可以放大也可以缩小 , 返回新的内存块的指针,分配失败返回null// 已经分配好的内存块指针--参数设置为null或者不写,会创建一个新的指针// 内存块的新大小 --------参数设置为0,会释放内存块//realloc不会对内存块进行初始化int* p = calloc(10, sizeof(int));float* new_p = realloc(p, sizeof(*p * 40));if (new_p == NULL) {printf("Error reallocing\n");return 1;}else{printf("win--- \n");}
}
拷贝内存:
memcpy拷贝:
#include <stdio.h>
#include <string.h>//自定义复制内存函数:
void* my_memcpy(void* dest, void* src, int byte_count) {char* s = src;char* d = dest;while (byte_count--) {*d++ = *s++;}return dest;}int main(){//memcpy(拷贝地址,被拷贝地址,拷贝的字节数) 前两个参数:不限制指针类型,各种类型的内存数据都可以拷贝char s[] = "Goats!";char t[100];// memcpy(t, s, sizeof(s)); // 拷贝7个字节,包括终止符int m = my_memcpy(t, s, sizeof(s));printf("m=%s\n", m); // "Goats!"return 0;
}
memmove复制:
#include <stdio.h>
#include <string.h>int main(){//memmove(拷贝地址,被拷贝地址,移动的字节数) 允许目标区域与源区域有重叠。如果发生重叠,源区域的内容会被更改char x[] = "Home Sweet Home";printf("x=%s\n", (char *) memmove(x, &x[5], 10));
}
比较内存:
memcmp:
#include <stdio.h>
#include <string.h>int main(){//memcmp(比对者1,比对者2,比较的字节数) 返回值:整数 //相同时返回0,参数一大于参数二时返回大于0,参数一小于参数二返回小于0// char* s1 = "abc";// char* s2 = "acd";// int r = memcmp(s1, s2, 3); // 小于 0// printf("memcmp result=%d",r);//比较内部带有字符串终止符\0的内存区域char s1[] = {'b', 'i', 'g', '\0', 'c', 'a', 'r'};char s2[] = {'b', 'i', 'g', '\0', 'c', 'a', 't'};printf ("3=%d \n",memcmp(s1, s2, 3) == 0) ;// trueprintf ("4=%d \n",memcmp(s1, s2, 4) == 0) ;// trueprintf ("7=%d \n",memcmp(s1, s2, 7) == 0) ;// false}
restrict 说明符 :
restrict :内存区域只有当前指针一种访问方式,其他指针不能读写该内存,这种指针称为“受限指针”(restrict pointer)