目录
C语言的特点:面相过程编程,C语言是将功能封装成一个函数,在按照一定的顺序调用,从而实现各种复杂功能的过程。
1、函数的概述
函数是C语言的功能单位。在封装函数时,一切以功能为准则,用功能来确定函数的形参、返回值、函数体、函数名。
2、函数的分类
按照定义分类:库函数,用户自定义函数、系统调用
按照参数分类:有参函数,无参函数
按照返回值分类:有返回值类型,无返回值类型
3、函数的定义
函数本身包括返回值类型、函数名、形参、函数体。
函数的定义:函数定义时,需要确定函数的返回值类型,函数名,形参个数、类型,实现函数体。
函数的声明:声明函数,是对函数的返回值类型,函数名,形参进行声明,不会实现函数体。
函数的调用:函数调用是使用函数名、形参等,对函数的使用。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//函数的声明
extern int add(int a,int b);
int main()
{
int sum = 0;
int data1 = 10;
int data2 = 5;
//函数的定义
sum = add(data1,data2);
printf("sum=%d\n",sum);
system("pause");
return 0;
}
//函数的定义
//int为函数的返回值类型;add为函数名;(int a,int b)为形参,用于传入外部值;{}中是函数体。
int add(int a,int b)
{
//返回一个运算结果
return a+b;
}
解释:
4、函数的形参
函数的形参:在定义函数时不为形参开辟空间,在调用函数时才为形参开辟空间。
4.1 普通变量作为函数的形参
普通变量作为函数形参时,函数内部变量,不能修改函数外部的值。
4.2 一维数组作为函数的形参
函数内部想要操作函数外部数组的值,只需要将数组名传递即可,这就导致函数的形参必须是数组。
// 函数的声明
void printf_arr(int num[5], int data);
int main()
{
int arr[5] = {1, 2, 3, 4, 5};
int arr_num = sizeof(arr) / sizeof(arr[0]);
int i = 0;
printf("调用函数前函数外部:");
for (i = 0; i < arr_num; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
printf_arr(arr, arr_num);
printf("调用函数后函数外部:");
for (i = 0; i < arr_num; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
system("pause");
return 0;
}
//此时形参的数组的[]号里面的元素个数可以省略
void printf_arr(int num[], int data)
{
int i = 0;
num[2] = 100; // 函数内部修改数组的值,函数外部数组的值也被修改
printf("函数内部:");
for (i = 0; i < data; i++)
{
printf("%d ", num[i]);
}
printf("\n");
return;
}
注:函数外部数组名 arr 等同于函数形参 num
解释:当一维数组作为函数参数时,传递进来的值被系统优化成指针变量(这个以后再讲,很重要),函数内部变量和函数外部变量都指向同一块内存空间,所以当在函数内部修改数组值后,函数外部的值也被修改,因为他俩是同一块内存。
4.3 二维数组作为函数的形参
函数内部形参可以操作函数外部数组的值。
void printf_arr(int num[][4], int row, int col);
int main()
{
int arr[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
int row = sizeof(arr) / sizeof(arr[0]);
int col = sizeof(arr[0]) / sizeof(arr[0][0]);
printf_arr(arr, row, col);
int i = 0, j = 0;
printf("函数外部:\n");
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
printf("\n");
system("pause");
return 0;
}
//二维数组作为函数形参可以省略行号,不能省略列号
void printf_arr(int num[][4], int row, int col)
{
int i = 0, j = 0;
num[1][1] = 100; // 函数内部修改数组的值,函数外部数组的值也被修改
printf("函数内部:\n");
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
printf("%d ", num[i][j]);
}
printf("\n");
}
return;
}
5、随机数
C语言中没有绝对的随机数,所谓的随机数都是将一个数据通过形参穿进去,之后后经过一系列计算,通过返回值传输出来的过程。
C语言中定义了rand()库函数,他就可以产生随机数。
在使用时,我们必须先设置随机数种子,通过srand()函数。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>//sranad函数,rand函数
#include <time.h>//time函数
int main()
{
//设置随机数种子,注意,随机数种子设置一次即可(也可反复设置),但是,在使用rand后最好不要重新设置,有可能导致数据重复
//time函数中保存的是1970年1月1日0时0分0秒到此时的秒数,以可以它为基准设置随机数种子
srand(time(NULL));
int i = 0;
for(i=0;i<10;i++)
{
//产生随机数,并打印
printf("%d\n",rand());
}
printf("\n");
system("pause");
return 0;
}
6、常用排序方法
6.1 选择排序
动画:
程序:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//选择排序
//系统优化后void selection_sort(int *data, int num)
void selection_sort(int data[], int num)
{
int i = 0;
for (i = 0; i < num - 1; i++)
{
int s, j;
for (s = i, j = s + 1; j < num; j++)
{
if (data[j] < data[s])
s = j;
}
if (s != i)
{
int tmp = data[s];
data[s] = data[i];
data[i] = tmp;
}
}
}
int main()
{
int arr[10] = {0};
int arr_num = sizeof(arr) / sizeof(arr[0]);
int i = 0;
// 获取键盘输入
printf("请输入%d个int型数据:",arr_num);
for (i = 0; i < arr_num; i++)
{
scanf("%d", &arr[i]);
}
// 选择排序
selection_sort(arr, arr_num);
// 遍历数组
for (i = 0; i < arr_num; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
system("pause");
return 0;
}
6.2 冒泡排序
动画:
程序:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// 冒泡排序
//系统优化后void bubble_sort(int *data, int num)
void bubble_sort(int data[], int num)
{
int i = 0;
for (i = 0; i < num - 1; i++)
{
int j = 0;
int flag = 0;
for (j = 0; j < num - i - 1; j++)
{
// 交换语句
if (data[j] > data[j + 1])
{
int tmp = data[j];
data[j] = data[j + 1];
data[j + 1] = tmp;
flag = 1;
}
}
if (flag == 0) // 说明内层循环没有一次交换 说明数组已经有序
{
break;
}
}
}
int main()
{
int arr[10] = {0};
int arr_num = sizeof(arr) / sizeof(arr[0]);
int i = 0;
// 获取键盘输入
printf("请输入%d个int型数据:", arr_num);
for (i = 0; i < arr_num; i++)
{
scanf("%d", &arr[i]);
}
// 冒泡排序
bubble_sort(arr, arr_num);
// 遍历数组
for (i = 0; i < arr_num; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
system("pause");
return 0;
}
7、字符串操作(分函数且不使用库函数)
7.1 字符串的长度测量(等价于strlen)
初学者版本:
// 测量字符串长度
// 系统优化成int my_strlen(char *sor)
int my_strlen(char sor[])
{
int num = 0;
while (sor[num] != '\0')
{
num++;
}
return num;
}
进阶者版本:
// 测量字符串长度
// 系统优化成int my_strlen(char *sor)
int my_strlen(char sor[])
{
int num = 0;
while (sor[num] && ++num);//利用了&&的短路特性 和 ++符号在前,先加后使用的特性
return num;
}
7.2 字符串逆序
字符串逆序,不是倒着输出,是将字符串倒过来。
//字符串逆序
//系统优化成void my_overturn(char *sor)
void my_overturn(char sor[])
{
// 数组首元素下标
int i = 0;
// 数组尾元素下标('\0'左边的元素)
int j = 0;
while (sor[j] && ++j); // 利用了&&的短路特性 和 ++符号在前,先加后使用的特性
j--; // 定位数组尾元素下标('\0'左边的元素)
// 元素交换
while (i < j)
{
char tem = sor[i];
sor[i] = sor[j];
sor[j] = tem;
i++;
j--;
}
}
7.3 字符串拷贝
//字符串拷贝:将sor的内容拷贝到des中
//系统优化成char* my_strcpy(char *des,char *sor)
//返回值类型为char*,即为拷贝后的数组名,初学者可以不用考虑返回值
char* my_strcpy(char des[],char sor[])
{
int i = 0;
while(sor[i])
{
des[i] = sor[i];
i++;
}
return des;
}
7.4 字符串追加
// 字符串追加:将sor的内容追加到des尾部
// 系统优化成char* my_strcat(char *des,char *sor)
// 返回值类型为char*,即为追加后的数组名,初学者可以不用考虑返回值
char *my_strcat(char des[], char sor[])
{
// 确定des的尾部
int i = 0;
while (des[i] && ++i)
;
// 确定sor的开头
int j = 0;
while (sor[j])
{
des[i++] = sor[j++]; // 利用++在后面,先使用后自增
}
des[i] = '\0'; // 为追加的字符串最后添加'\0'
return des;
}
7.5 字符查找
// 字符查找:从sor中查找ch字符
// 系统优化成int my_strchr(char *sor,int ch)
// 返回值类型为int,返回的是字符下标,未找到返回-1
int my_strchr(char sor[], int ch)//在库函数中一般使用int类型存放字符类型的数据
{
int i = 0;
while (sor[i] != '\0')
{
if (sor[i] == ch)
break;
i++;
}
if (sor[i] == '\0')
return -1;
return i;
}
7.6 字符删除
// 字符删除:将sor的中的下标为pos的字符删除
// 系统优化成char* my_delete(char *sor,int pos)
// 返回值类型为char*,即为删除后的数组名,初学者可以不用考虑返回值
char *my_delete(char sor[], int pos)
{
// 判断pos的有效性
int len = 0;
while (sor[len] && ++len)
;
if (!(pos >= 0 && pos < len))
{
printf("输入的下标位置无效,删除失败!!!\n");
return sor;
}
// 进行删除动作(移动元素)
while (sor[pos] != '\0')
{
sor[pos] = sor[pos + 1];
pos++;
}
return sor;
}
7.7 字符串的指定位置插入新字符串
// 字符串插入:将sor的插入到des字符串的pos下标位置中
// 系统优化成char *my_insertion(char des[], char sor[],int pos)
// 返回值类型为char*,即为插入后的数组名,初学者可以不用考虑返回值
char *my_insertion(char des[], char sor[],int pos)
{
// 1、获取des和sor的长度
int len1 = 0, len2 = 0;
while (des[len1] && ++len1)
;
while (sor[len2] && ++len2)
;
// 2、判断pos的合法性
if (!(pos >= 0 && pos <= len1))
{
printf("输入的下标位置无效,插入失败!!!\n");
return des;
}
// 3、移动数据保证足够的插入位置(从尾元素开始移动)
int i = len1;
while (i >= pos)
{
des[i + len2] = des[i];
i--;
}
// 4、将sor的逐个元素插入到pos位置中
int j = 0;
while (sor[j] != '\0')
{
des[pos] = sor[j];
pos++;
j++;
}
return des;
}