【1】函数
1.定义:
函数是一个完成特定功能的代码模块,其程序代码独立。
2.格式:
(存储类型) 数据类型 函数名(形式参数) { 函数体; return 常量、变量或表达式; } int add(int a, int b) { return a + b; }
3.调用:
函数名(实参);
4.声明:
数据类型 函数名(形式参数);
int add(int a, int b);
int add(int, int);
5.函数的传参:
1)值传递:只是将值进行传递,对传递的值不会产生影响(复制传递)。
2)地址传递:将地址进行传递,在子函数中改变地址中的内容时,会对主函数的变量的值产生影响。
3)数组传递:int array(int a[], int n)
进行数组传递时,并没有将整个数组进行传递,而是传递的是数组的首地址。
【2】指针函数
1.本质:
函数,函数的返回值为指针(地址)
2.格式:
数据类型 *函数名(参数)
{
return 地址;//return NULL;
}
代码示例(如下):
#include <stdio.h>
int add(int, int);
int main(int argc, char const *argv[])
{
// int (*p)(int, int) = add;
int (*p)(int, int) = NULL;
p = add;
printf("%d\n", add(3, 4));
printf("%d\n", p(5, 6));
return 0;
}
int add(int a, int b)
{
return a + b;
}
// 7
// 11
【3】函数指针:
1.本质:
指针,指向函数的指针
char st[] = "hello";
char *p = st;
用指针(p)代替st,st
什么类型的指针指向什么类型的数
int a;int *p;
char ch,char *q;
2.格式:
数据类型 (*函数指针变量名)(参数);
3.用法:
1)当一个函数指针指向了一个函数,就可以通过这个指针来调用该函数,
2)函数指针可以将函数作为参数传递给其他函数调用。
代码示例(如下):
#include <stdio.h>
#include <signal.h>
void fun(int sig)
{
printf("***************\n");
}
int main(int argc, char const *argv[])
{
signal(SIGINT, fun);//同步运行,若while在sianal()上边,直接执行死循环,不会调用子函数
while (1);//异步运行
return 0;
}
4.指针函数和函数指针分别在什么地方用过?
1)指针函数
当需要这个函数返回地址时。
2)函数指针
signal函数参数 (信号处理函数)
pthread_create函数的参数 (线程的处理函数)
底层(file_operations结构体里成员())
5.要求:
1:知道函数指针,能倒退还原函数
2:有函数,要让指针指向这个函数,要能定义出函数指针
注意:数据类型(返回值的数据类型,参数的数据类型)
代码示例(如下):
#include <stdio.h>
int add(int i, int j);//函数声明(格式一致)
int fun(int a, int (*p)(int b, int c));//函数声明(格式一致)
int main(int argc, char const *argv[])
{
printf("%d\n", fun(10, add)); //函数首地址
return 0;
}
int add(int i, int j)
{ //形参被实参覆盖
return i + j;
}
//两个参数:第一个整型,第二个函数指针
int fun(int a, int (*p)(int b, int c))
{
return a + p(3, 5); //定义实参
}
// 18
【4】函数指针数组
1.本质:
数组,数组的内容为函数指针
2.格式:
数据类型 (*函数指针数组名[个数])(参数);
代码示例(如下):
#include <stdio.h>
int add(int a, int b)
{
return a + b;
}
int fun(int a, int b)
{
return a - b;
}
int mul(int a, int b)
{
return a * b;
}
int main(int argc, char const *argv[])
{
int (*p[3])(int, int) = {add, fun, mul};//函数指针数组
int i = 0;
for (i = 0; i < 3; i++)
{
printf("%d\n", p[i](3, 2));
}
return 0;
}
// 5
// 1
// 6
【5】解决问题—>准确定位(行)
使用过的调试方式有哪些?
1:GDB
(在用GDB调试之前确定你的代码没有语法错误。设置断点的时候,必须让主函数运行起来,第一次断点设置,设置在主函数当中的某一行,这样编译器才能从入口函数进来)
在gcc编译选项中一定要加入‘-g’。
只有在代码处于“运行”或“暂停”状态时才能查看变量值。
设置断点后程序在指定行之前停止
1) gcc -g test.c
2) gdb a.out
3)(gdb)l:列出源文件内容
4)(gdb)b 10:设置断点在第10行
5)(gdb)r :运行(设置断点后一定要先运行,才能进行单步调试往下)
6)(gdb)n:单步调试(断点行是不被运行的,n单步调试的时候不进子函数)
7)(gdb)s:单步运行(断点行是不被运行的,s单步调试的时候进子函数)
8)(gdb)p 变量名 :查看变量值
9) q:退出调试界面
2:printf打印
printf("%s,%s,%d\n",__FILE__,__func__,__LINE__);
1)大概定位(缩小范围)
2)作用:定位错误。
如果这一行打印,那么引起错误的代码肯定在这一行之后;
如果这一行没有打印,那么引起错误的代码肯定在这一行之前。
代码示例(如下):
#include <stdio.h>
#include <string.h>
int fun()
{
int i = 3;
int j = 4;
printf("i:%d j:%d\n", i, j);
}
int main(int argc, char const *argv[])
{
fun();
int a = 3;
int b = 4;
char *p = NULL;
printf("%s %s %d\n", __FILE__, __func__, __LINE__);
//无法定位到哪一行,只能缩小范围(名文件_函数名_行数)
strcpy(p, "hello");
printf("%s\n", p);
return 0;
}