12 函数

系列文章目录

提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加

例如:第一章 Python 机器学习入门之pandas的使用


提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

提示:这里可以添加本文要记录的大概内容:

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、基本概念

main函数

main函数可带参也可不带参

带参形式:

c 复制代码
int main(int argc,char *argv[]){
	printf("argc = %d\n",argc);	//打印1
	printf("%s\n",argv[0]);	//打印./a.out
	return 0;
}
  • argv :接收来自命令行的各个字符串参数,
    • argv[0]为:./该程序文件名
    • argv[1]argv[argc-1] 是用户传入的参数。
  • argc :记录了接收字符串的个数

函数的组成结构

函数是一个完成特定功能的代码模块,其程序代码独立,通常要求有返回值,也可以是空值。
函数定义

c 复制代码
<数据类型> <函数名称>( <形式参数说明> ) {
	语句序列;
	return[(<表达式>)];
}
  • <数据类型> 是整个函数的返回值类型。如无返回值应该写为void
  • return[(<表达式>)]语句中表达式的值,要和<数据类型>保持一致。
  • <形式参数说明>是以逗号""分隔的多个变量的说明形式
  • 大括弧对 {<语句序列> },称为函数体;<语句序列>是大于等于零个语句构成的

函数的调用

函数的使用就叫函数调用,形式如下:

c 复制代码
函数名称(〈实际参数〉)
  • 对于无返回值的函数来讲,只能形成一个函数调用语句。
  • 函数调用可以作为一个运算量出现在表达式中,也可以单独形成一个语句。
  • 实参就是在使用函数时,调用函数传递给被调用函数的数据。
c 复制代码
#include <stdio.h>
int get_max(int a, int b){	//函数定义
    if(a > b)
        return a;
    else
        return b;
}

int main(int argc,const char *argv[]){
    int max;
    int a = 29,b = 60;

    max = get_max(a,b); //函数调用
    printf("%d\n",max);
    return 0;
}

函数的声明

编译器从上往下顺序进行编译,如果函数定义在调用之后,就需要在调用之前进行函数声明。如:

c 复制代码
#include <stdio.h>
int get_max(int, int b);	//先声明在使用,否之编译到调用的时候编译器没见过该函数,它不认识
int main(int argc,const char *argv[]){
    int max;
    int a = 29,b = 60;

    max = get_max(a,b); //函数调用
    printf("%d\n",max);
    return 0;
}
int get_max(int a, int b){	//函数定义在调用之后
    if(a > b)
        return a;
    else
        return b;
}

其中,<形式参数说明>可以缺省说明的变量名称,但类型不能缺省。就算变量名与定义不一致也没问题。但返回类型,函数名,参数类型和参数个数要与定义时保持一致。

:定义求x^n值的函数(x是实数, n为正整数)

c 复制代码
#include <stdio.h>

double pow_fun(double x, unsigned int n){
    double sum = 1.0;
    for(;n > 0; n--){
        sum *= x;
    }
    return sum;
}

int main(int argc,const char *argv[]){
    int n;
    double x,ret;

    scanf("%lf%d",&x,&n);
    ret = pow_fun(x,n);
    printf("%lf\n",ret);
    return 0;
}

二、函数传参

参数概念

形参

  • 形参,全称为"形式参数"
  • 形参是在定义函数的时候使用的参数
  • 目的是用来接收调用该函数时传递的参数

实参

  • 实参,全称为"实际参数"
  • 实参是在调用时传递给函数的参数,即传递给被调用函数的值。
  • 在主调函数中调用一个函数时,函数名后面括弧中的参数(可以是一个表达式)称为"实际参数"。

参数传递

  • 在程序运行过程中,将实际参数的值或者地址传递给被调用函数的形式参数,从而在函数中完成对数据处理和返回的过程。

  • 在C语言当中,参数的传递方式本质上只有一种,就是值传递

  • 但为了更好区分理解,划分了三种方式

    • 全局变量
    • 值传递方式
    • 指针传递方式
  • 核心原则:一切皆为值传递

全局变量

  • 全局变量就是在函数体外(所有函数外)说明的变量
  • 全局变量一经定义后就会在程序的任何地方可见。
  • 函数调用的位置不同,程序的执行结果可能会受到影响。不建议使用

值传递

  • 调用函数将实参传递给被调用函数,被调用函数将创建同类型的形参并用实参初始化
  • 形参是新开辟的存储空间,在函数中改变形参的值,不会影响到实参
  • 示意图
  • C 语言在调用函数时,会将实参的值复制一份 传递给形参。形参和实参在内存中位于不同的位置,形参是实参的副本

:值传递是否可以交换两个变量的值

c 复制代码
#include <stdio.h>

void fun_swap(int a, int b);
int main() {
	int x = 200, y = 100;
	
	printf("before:x=%d y=%d %p %p\n", x, y, &x, &y);
	fun_swap(x, y);
	printf("after:x=%d y=%d\n", x, y);	//x=200 y=100
	return 0;
}

void fun_swap(int a, int b) {//int a=x; int b=y;
	int t = a;
	a = b;
	b = t;
	printf("a=%d b=%d %p %p\n", a, b, &a, &b);	//a=100 b=200, 修改的是形参副本
}

从内存视角看:

  • 调用 fun_swap(x, y) 时,系统在栈上为形参 a,b 分配空间,并将 x,y 的值复制到 a,b 中。

  • 函数内部修改a,b不影响外部的 x,y

指针传递

如果想在函数内部修改外部的变量,就必须传递变量的地址 (指针)。此时复制的是地址值,函数通过该地址可以间接访问原始变量。

  • 按地址传递,实参为变量的地址,而形参为同类型的指针
  • 被调用函数中对形参的操作,将直接改变实参的值
  • 被调用函数对指针的目标操作,相当于对实参本身的操作

:实现两个数交换的函数

c 复制代码
#include <stdio.h>

void fun_swap(int *, int *);
int main() {
    int x = 200, y = 100;

    printf("before:x=%d y=%d %p %p\n", x, y, &x, &y);
    fun_swap(&x, &y);		//复制x和y的地址给形参变量a,b,此时a,b指向x,y的内存位置,解引用后修改x,y本身
    printf("after:x=%d y=%d\n", x, y);  //x=200 y=100
    return 0;
}

void fun_swap(int *a, int *b) {
    int t = *a;
    *a = *b;
    *b = t;
    printf("a=%d b=%d %p %p\n", *a, *b, &a, &b);    //a=100 b=200
}

例: 编写一个函数,统计字符串中小写字母的个数,并把字符串中的小写字母转化成大写字母

c 复制代码
#include <stdio.h>

int fun_string(char *);
int main() {
    char s[100];
    int n;

    fgets(s,100,stdin);
    n = fun_string(s);
    printf("%s%d\n",s,n);
    return 0;
}

int fun_string(char *p) {
    int t = 0;
    while(*p != '\0'){
        if(*p >= 'a' && *p <= 'z'){
            *p -= 32;
            t++;
        }
        p++;
    }
    return t;
}

一维数组在函数间传参

传递参数是普通数组

数组名形式的传参

当数组名作为实参传递时,它自动退化为指向首元素的指针 。形参可以写成数组形式或指针形式,二者完全等价。

c 复制代码
void fun(int arr[ ], int size) ;
void fun(int *arr, int size) ;
void fun(int arr[10], int size) ;// 长度10被忽略,仅起文档作用
  • size用来指定数元素个数。
  • 关键点 :在函数内部 sizeof(arr) 得到的是指针的大小(4 或 8 字节),而不是整个数组的大小。因此必须额外传递数组长度

:编写函数,计算一个一维整形数组的所有元素的和

c 复制代码
#include <stdio.h>

int fun(int *,int);
int fun1(int [],int);

int main() {
    int arr[] = {100,1,2,3,4,5,6,7,8,9};
    int n = sizeof(arr) / sizeof(int);
    int add = fun(arr,n);
    int add1 = fun1(arr,n);

    printf("%d\n%d\n",add,add1);
    return 0;
}

int fun(int *p,int size){
        int add = 0;
        for(int i = 0; i < size; i++){
            add += *p++;
        }
        return add;

}
int fun1(int p[],int size){
		printf("%ld\n",sizeof(p));	//打印的是8,并不是数组的大小,本质还是指针
        int add = 0;
        for(int i = 0; i < size; i++){
            add += p[i];
        }
        return add;
}

例: 对整型数组进行排序,编写排序函数

c 复制代码
#include <stdio.h>
#include <stdbool.h>

void fun(int *,int);

int main() {
    int arr[] = {100,11,256,39,48,500,656,76,8,91};
    int n = sizeof(arr) / sizeof(int);
    fun(arr,n);

    for(int i = 0; i < n; i++){
        printf("%d ",arr[i]);
    }
    putchar('\n');

    return 0;
}

void fun(int *p,int size){
    int t = 0;
    bool flag = true;
    for(int i = 0; i < size-1; i++){
        if(!flag){
            break;
        }
        flag = false;
        for(int j = 0; j < size-1 -i; j++){
            if(*(p+j) > *(p+j+1)){
                t = *(p+j);
                *(p+j) = *(p+j+1);
                *(p+j+1) = t;
                flag = true;
            }
        }
    }
}

字符数组传参

c 复制代码
#include <stdio.h>
#include <stdbool.h>

void del_space(char *);

int main() {
    char s[100] = "  abcd   efg   hijk  ";

    del_space(s);

    printf("%s\n",s);
    return 0;
}

void del_space(char *s){
    char *p = s;
    char *q = s;

    while(*p != '\0'){
        if(*p != ' '){
            *q = *p;
            p++;
            q++;
        }else{
            p++;
        }
    }
    *q = '\0';
}
/*
void del_space(char *s){
    char *p = s;
    char *q = s;
    while(*p != '\0'){
        if((*p != ' ' && *q != ' ') || (*p == ' ' && *q != ' ')){
            p++;
            q++;
        
        }else if(*p == ' ' && *q == ' '){
            p++;

        }else if(*p != ' ' && *q == ' '){
            *q = *p;
            *p = ' ';
            p++;
            q++;
        }else{
            p++;
        }
    }
}
*/

二维数组(及多维数组)传参

同样会退化,但只能省略第一维的长度,其余维度必须明确指定。

二维数组在函数间传参 - 一级指针

c 复制代码
const int N = 2;//要改变二维数组的行和列
const int M = 3;//只需改变这里即可
void fun(int*,int ,int);

这时实参写一维数组名arr[0],会退化为首元素指针(&arr[0][0])

c 复制代码
#include <stdio.h>

void print_array(int *a,int n,int m);

int main() {
    int arr[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};

    print_array(arr[0],3,4);
    return 0;
}

void print_array(int *a,int n,int m){
    for(int i = 0; i < n * m; i++){
        printf("%d ",*a++);
    }
}

二维数组在函数间传参 - 行指针

c 复制代码
const int N = 2;//要改变二维数组的行和列
const int M = 3;//只需改变这里即可
void fun(int array[][M], int, int);	//列数必须明确
//等价写法
void fun(int (*array)[M], int, int);

这时实参写二维数组名arr,退化为行指针(&arr[0])

:编写函数,计算一个二维整形数组的奇数的个数

c 复制代码
#include <stdio.h>

//int get_odd(int (*a)[4],int n,int m);//两种形式等价
int get_odd(int a[][4],int n,int m);
int main() {
    int arr[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
    int ret = get_odd(arr,3,4);
    printf("ret = %d\n",ret);
    return 0;
}


int get_odd(int a[][4],int n,int m){
    int i,j,sum = 0;
    for (i = 0; i < n; i++){
        for(j = 0; j < m; j++){
            if(a[i][j] % 2 != 0)
                sum ++;
        }
    }
    return sum;
}

二维数组在函数间传参 - 二级指针

c 复制代码
const int N = 2;//要改变二维数组的行和列
const int M = 3;//只需改变这里即可
void fun(int**, int, int);

这时实参是一个二级指针

c 复制代码
#include <stdio.h>

int get_odd2(int ** a, int n, int m);

int main() {
    int a[3][4] = {{1, 5, 3, 2}, {3, 6, 9, 8}, {2, 5, 9, 6}};
    int * p[3] = {a[0], a[1], a[2]};
    int r;

    r = get_odd2(p, 3, 4);
    printf("r=%d\n", r);
    return 0;
}

int get_odd2(int ** a, int n, int m ) {
    int i, j, sum = 0;
    for (i = 0; i < n; i++) {
        for (j = 0; j < m; j++) {
            if (*(a[i]+j) % 2 != 0) {
                sum++;
            }
        }
    }
    return sum;
}

三、指针函数

定义:返回值为指针的函数

c 复制代码
int * fun(int x, int y);	//声明

数据类型 * 函数名(参数列表){		//定义
	//函数体
}

因为( )优先级更高,所以 fun与后面的括号结合,是函数名,调用它以后返回一个int ∗ 型的指针。

不能返回局部变量的指针,运行时可能出错

指针函数中可以返回什么样的指针?

  • 全局变量的地址
  • 字符串常量的地址
  • static变量的地址
  • 堆的地址
  • 主调函数中有效内存
c 复制代码
#include <stdio.h>
char * mystring( ) {
	char *s = "hello world";	//s是静态常量的地址,可以返回
	return str;
}
char *get_char(){
	char ch[10] = "hello";
	return ch;	//返回局部变量的地址,编译器可能警告
}
int main(void) {
	printf("%s\n", mystring());
	printf("%s\n",get_char());	//可能运行失败
	return 0;
}

:实现字符串拷贝strcpy

c 复制代码
#include <stdio.h>
#include <assert.h>

char *my_strcpy(char *dest, const char *src);

int main(void) {
    char *ch = "  hello hhhhhhhhh hhhhhhhh  ";
    char arr[100];
    char *s;

    s = my_strcpy(arr,ch);
    printf("%s\n",s);
    return 0;
}


char *my_strcpy(char *dest, const char *src){

/*	if(dest == NULL || src == NULL){
		return NULL;
	}
*/
	assert(dest && src);	//检查两个指针是否为NULL
    char *p = dest;
    while(*src != '\0'){
        *dest = *src;
        src++;
        dest++;
        //*dest++ = *src++;	写法2
    }
    //*dest = '\0';
    *dest = *src;	//此时*src就是'\0'
    /*while(*dest++ = *src++); 写法3*/
    return p;
}

assert用法

assert 是 标准库中用于程序调试的宏 ,定义在 <assert.h> 头文件中。

c 复制代码
#undef assert
#ifdef NDEBUG
    #define assert(expr) ((void)0)
#else
    #define assert(expr) \
        ((expr) ? (void)0 : \
         __assert_fail(#expr, __FILE__, __LINE__, __func__))
#endif

用法:

c 复制代码
#include <assert.h>

assert(表达式);

作用

  • 当 NDEBUG 定义时:assert(expr) 被替换为 ((void)0),什么也不做。

  • 当 NDEBUG 未定义时:在程序运行时检查一个条件表达式,如果条件为假(0),则向标准错误输出一条错误信息并终止程序;如果条件为真(非0),则什么都不做,继续执行。

  • assert 只在 调试阶段 使用。在最终发布的程序中,通常会关闭所有 assert 检查,以避免性能损失。方法是在包含 <assert.h> 之前 定义宏 NDEBUG

    c 复制代码
    #define NDEBUG          // 放在 #include <assert.h> 之前
    #include <assert.h>

:实现字符串连接

c 复制代码
#include <stdio.h>

char *my_strcat(char *dest, const char *src);

int main(void) {
    char *ch1 = "  hello hhhhhhhhh hhhhhhhh  ";
    char ch2[100] = " JHASHb jJABi b";
    char *s;

    s = my_strcat(ch2,ch1);
    printf("%s\n",s);
    return 0;
}


char *my_strcat(char *dest, const char *src){
    char *p = dest;
    while(*src != '\0'){
        if(*dest != '\0'){
            dest++;
        }  
        else{
            *dest = *src;
            src++;
            dest++;
         }
     }
    *dest = *src;		//边界问题,当src为空时,dest被截断,此处需要做处理
    return p;
}

直接分两段循环,思路更清晰。

c 复制代码
char *my_strcat(char *dest, const char *src) {
    char *p = dest;
    while (*dest) dest++;          // 找到 '\0'
    while ((*dest++ = *src++));    // 复制,包括最后的 '\0'
    return p;
}

:编写一个指针函数,把整数123转化成字符串"123"

c 复制代码
#include <stdio.h>

char *my_intchar(char *p,int num);
int main(void) {
    int n;
    char arr[30],*s;
    scanf("%d",&n);

    s = my_intchar(arr,n);
    printf("%s\n%s\n",s,arr);


    return 0;
}

char *my_intchar(char *p, int num){
    int i = 0,t = 0;
    while(num != 0){
        p[i] = num % 10 + 48;
        num = num / 10;
        i++;
    }
    p[i] = '\0';

    for(int j = 0; j < i / 2; j++){
        t = p[j];
        p[j] = p[i-1-j];
        p[i-1-j] = t;
    }
    return p;
}

四、函数指针

定义

  • 函数指针,即函数的入口地址
  • 函数名代表函数的入口地址(右值)

函数指针变量一般形式

c 复制代码
<数据类型> (*<函数指针名称>)(<参数说明列表>);

int (*p)(int ,int);

指针p的类型是:int (*)(int,int)
  • <数据类型>是函数指针所指向的函数的返回值类型
  • <参数说明列表>应该与函数指针所指向的函数的形参说明保持一致
  • (*<函数指针名称>)中,*说明为指针,()优先结合,不可缺省,表明为函数的指针

函数指针的调用

  • 同函数名(非标准)

  • 解引用(标准)

    c 复制代码
    #include <stdio.h>
    
    int add(int a, int b) { return a + b; }
    int sub(int a, int b) { return a - b; }
    int mul(int a, int b) { return a * b; }
    int div(int a, int b) { return a / b; }
    double f(double a, double b) {return a + b;}
    int fun_arith(int a, int b, int (*p)(int, int)) {//int (*p)(int, int) = add;
    	return p(a, b);												 
    }
    
    int main() {
    	int m , n;
    	int (* p)(int, int);
    
    	scanf("%d%d", &m, &n);
    
    	p = add;
    	printf("+ %d\n", p(m, n));
    	p = sub;
    	printf("- %d\n", (*p)(m, n));
    	p = mul;
    	printf("* %d\n", p(m, n));
    	p = div;
    	printf("/ %d\n", p(m, n));
    	//p = f;error
    	
    	printf("fun_arith:%d\n", fun_arith(m, n, add));
    
    	return 0;
    }

函数指针数组

函数指针数组是一个保存若干个函数名的数组

一般形式:

c 复制代码
<数据类型> (*<函数指针数组名称> [<大小>] )(<参数说明列表> );
int (*arr[4])(int int);

在函数指针基础上加个大小就行,大小表示数组中函数名的个数

c 复制代码
#include <stdio.h>

int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mul(int a, int b) { return a * b; }
int div(int a, int b) { return a / b; }

int main() {
	int m , n, i;
	int (* p[4])(int, int);

	scanf("%d%d", &m, &n);
	
	p[0] = add;
	p[1] = sub;
	p[2] = mul;
	p[3] = div;

	for (i = 0; i < 4; i++) {
		printf("%d\n", p[i](m, n));
	}
	return 0;
}

qsort函数

通用快速排序函数 ,它能对任意类型 的数组进行排序,你只需要提供一个比较函数 ,告诉 qsort 如何判断两个元素的大小关系。

c 复制代码
void qsort(void *base,size_t nmemb,size_t size,int(*comper)(const void *,const void*));
  • base:数组首元素地址
  • nmemb:数组元素个数
  • size:数组元素大小
  • comper:比较函数指针

比较函数需要自己实现:

对整数数组排序:

c 复制代码
int cmp_int(const void *a, const void *b) {
    int ia = *(int *)a;	//转成对应类型
    int ib = *(int *)b;
    //return ia - ib;   // 升序,注意只能用于较小值的比较,因为很大的整数-负数会溢出
    // 若要降序,返回 ib - ia
    return (a>b) - (a<b)	//升序
    //降序,返回:(b>a)-(b<a);
}

对字符串数组排序:

c 复制代码
int cmp_string(const void *a, const void *b) {
    // a 和 b 都是指向 char* 的指针
    const char **sa = (const char **)a;
    const char **sb = (const char **)b;
    return strcmp(*sa, *sb);	//字符串比较函数
}

浮点数组排序函数:

c 复制代码
// 升序比较函数
int cmp_double(const void *a, const void *b) {
    double da = *(const double *)a;
    double db = *(const double *)b;
    if (da < db) return -1;
    if (da > db) return 1;
    return 0;
}

// 或者更简洁的写法(利用 (da > db) - (da < db) 返回 -1/0/1)
int cmp_double2(const void *a, const void *b) {
    double da = *(const double *)a;
    double db = *(const double *)b;
    return (da > db) - (da < db);
}

字符数组比较函数:

c 复制代码
int cmp_char(const void *a, const void *b) {
    // 直接返回差值,因为 char 可以安全转换为 int 且范围小
    return *(const char *)a - *(const char *)b;
}

五、递归函数

  • 函数体中直接或间接调用该函数自身
  • 必须要有结束条件
  • 递归函数的执行过程分为两个阶段:
    • 递推阶段:从原问题出发,按递归公式递推从未知到已知,最终达到递归终止条件
    • 回归阶段:按递归终止条件求出结果,逆向逐步代入递归公式,回归到原问题求解
  • 递归函数可以简化代码结构,可能导致栈溢出
    :递归函数计算n!
c 复制代码
#include <stdio.h>

int fac(int);

int main(void) {
    int n,ret;
    scanf("%d",&n);
    ret = fac(n);
    printf("n! = %d\n",ret);
    return 0;
}

int fac(int n){
    if(n == 1){
        return 1;
    }
    return n * fac(n-1);
}

:递归函数,计算斐波那契数列

其数值为:1、1、2、3、5、8、13、21、34...... 在数学上,这一数列以如下递推的方法定义:

F(0)=1,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2)

c 复制代码
#include <stdio.h>

int fid(int);

int main(void) {
    int n,ret;
    scanf("%d",&n);

    for(int i = 1; i <= n; i++){
        printf("%d ",fid(i));
    }
    return 0;
}

int fid(int n){
    if(n == 1 || n == 2){
        return 1;
    }
    return fid(n-1) + fid(n-2);
}

:下列代码输出什么?

c 复制代码
#include <stdio.h>

void printNumbers(int n) {
    if (n < 0) return;
    printf("%d ", n);
    printNumbers(n - 1);
}

int main() {
    printNumbers(5);
    return 0;
}

答:5 4 3 2 1 0

六、字符串操作函数

字符串长度

c 复制代码
size_t strlen(const char *s);

返回字符串长度,字符长度不包括'\0'

c 复制代码
char s[10]={'A','\0','B','C','\0','D'};
char s[ ]="\t\v\\\0will\n"; //\t:(水平制表符)tab ,\v垂直制表符,\\:\本身
char s[ ]="\x69\141\n"; //\xhh表示十六进制数代表的符号 \ddd表示8进制的

字符串拷贝

c 复制代码
char *strcpy(char *dest, const char *src);	//将src指向全部拷贝dest,连同'\0'
char *strncpy(char *dest, const char *src, size_t n);	//将src中指定的前n个字符拷贝到dest,如果n小于或等于源字符串的长度,目标串不会自动加'\0',需要手动加'\0'。
//如果源字符串的长度小于n,则复制完源字符串后,会用'\0'填充指定的剩余的空间。

返回dest

要确保dest指向空间足够

c 复制代码
#include <stdio.h>
#include <string.h>
int main() {
	char dest[20] = "**********";
	char src[] = "hello world!";
	strncpy(dest, src, 8);	//将src的前8个字符复制到dest中
	dest[8] = '\0';		//由于源字符串的长度大于或等于n,我们需要在dest的后面添加'\0'。
	printf("%s\n", dest);	//helllo wr  如果不手动加'\0',输出:hello wo**
	return 0;
}
c 复制代码
#include <stdio.h>
#include <string.h>
int main() {
	char dest[20] = "**********";
	char src[] = "hello";
	strncpy(dest, src, 8);
	//dest[8] = '\0';
	printf("%s\n", dest);	//hello
	//此时dest的内容: hello\0\0\0\0**\0\0....;源字符串的长度小于n,则复制完源字符串后,会用'\0'填充指定的剩余的空间。
	return 0;
}

字符串链接

c 复制代码
char *strcat(char *dest, const char *src);	//连接前,两串均以'\0'结束;连接后,串1的 '\0'取消,新串最后加'\0'
char *strncat(char *dest, const char *src, size_t n);	//源字符串的长度小于n,会将源字符串的全部字符追加到目标字符串中。
//源字符串的长度大于或等于n,则只会将源字符串的前n个字符追加到目标字符串中。自动追加'\0'

字符串比较

c 复制代码
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);	//两个字符串的前n个字符进行比较

对两串从左向右逐个字符比较(ASCII码相减),直到遇到不同字符或'\0'为止。若差值为零则继续比较下去;若差值不为零,则返回差值。

a. 若字符串1< 字符串2, 返回负整数

b. 若字符串1> 字符串2, 返回正整数

c. 若字符串1== 字符串2, 返回零

字符串中查找字符

c 复制代码
char *strchr(const char *s, int c);	//返回首次出现c的指针。找不到返回NULL
char *strrchr(const char *s, int c);	//返回最后一次出现c的指针。找不到返回NULL
char *strchrnul(const char *s, int c);	//返回最后一次出现c的指针。找不到返回指向s结尾处空字节的指针,而不是NULL。

字符串中查找子串

c 复制代码
char *strstr(const char *haystack, const char *needle);	//找子串,区分大小写
char *strcasestr(const char *haystack, const char *needle);	//在字串,不区分大小写

返回首个相同字串的首地址,找不到返回NULL

匹配过程不包括终止'\0',但它到此为止。

七、字符操作函数

需要头文件:#include <ctype.h>

判断一个字符是否为字母

c 复制代码
int isalpha(int c);

返回:0-不是字母,非0-是字母

判一个字符是否为大写字母

c 复制代码
int isupper(int c);

返回:0-不是大写字母 非0-是大写字母

c 复制代码
int islower(int c)	//判断是否为小写字母
int isdigit(int c)	//判断是否为数字字符
int isblank(int c)	//判断是否为空白字符

小写转大写

c 复制代码
int toupper(int c);
int toupper_l(int c, locale_t locale);//可以指定语言环境

如果参数c不是小写字母就不转换

返回:转换后的结果

在 默认的 "C" locale(或 "POSIX" locale)下,toupper() 只对 ASCII 小写字母 'a'--'z' 进行转换,返回对应的大写字母 'A'--'Z'

大写转小写

c 复制代码
int tolower(int c);

如果给定的字符不是大写字母,则不对它做任何处理,也不会报错或者警告。

返回:小写字母;或原样返回(传入非大写字母时)

相关推荐
小文数模2 小时前
2026 年MathorCup(妈妈杯)数学建模竞赛C完整参考论文(第一版)
c语言·数学建模·matlab
汽车芯猿2 小时前
嵌入式 SHA-256 完全实现(附原码)(无 uint64_t,减少栈使用)
c语言·单片机
wuminyu2 小时前
专家视角看Java的线程是如何run起来的过程
java·linux·c语言·jvm·c++
码农的神经元2 小时前
2026 MathorCup 选题建议:A/B/C/D/E 题到底怎么选?
c语言·开发语言·数学建模
聆风吟º3 小时前
【C标准库】深入理解C语言strcmp函数:字符串比较的核心用法
c语言·开发语言·库函数·strcmp
weixin_446023563 小时前
C语言入门:发展历程与编程应用
c语言·基础知识·发展历程·语法结构·编程应用
良木生香3 小时前
【C++初阶】:泛型编程的代表作---C++初阶模板
c语言·开发语言·数据结构·c++·算法
yashuk3 小时前
C语言中强制类型转换:不同数据类型间的转换方法与示例
c语言·强制类型转换·示例代码·注意事项·数据类型转换
计算机安禾4 小时前
【数据结构与算法】第48篇:算法思想(三):贪心算法
c语言·开发语言·数据结构·算法·贪心算法·代理模式·图论