指针:
含义:是一个值,一个值代表着一个内存地址,类似于存放路径
* 运算符 :
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) {
}