C语言知识(10)

函数

IO函数
字符串操作函数
字符操作函数
内存操作函数 memset
时间/日期函数
数学函数 sqrt
其他库函数

交换两数

void Swap(int* pa, int* pb)//传地址 形参
{
        int tmp = 0;
        tmp = *pa;
        *pa = *pb;
        *pb = tmp;
}
int main()
{
        int a = 10;
        int b = 20;
        Swap(&a,&b);//实参
        printf("%d %d\n", a, b);
}

实参:真实传给函数的参数 可以是常量、变量、表达式、函数
形参:是指函数名括号中的变量
传值调用:当实参传给形参的时候,形参实际上实参的临时拷贝,函数的形参和实参分别占着不同内存块,对形参的修改不会影响实参(不对数进行操作,找出最大数)
传址调用:把函数外部创建变量的内存地址传递给函数参数,函数内部可以直接调用函外部的变量(对数进行操作,两数交换)

//每调用一次函数,num+1
//函数的声明 //声明有这个函数,只是在主函数的后面//num可以省略,声明中不会用到
void Add1(int* num)int main()
{
        int num = 0;
        Add1(&num);//函数要操作num,传址
        printf("%d", num);
}
//函数的定义
void Add1(int* num)
{
        (*num)++;//解引用
}

函数的嵌套调用:函数和函数之间可以有机的组合
函数的链式访问:把一个函数的返回值作为另一个函数的参数

printf返回的是整型的字符串个数

int main()
{
        printf("%d", printf("%d", printf("%d", 43)));//4321
}

函数的声明放在.h头文件中,函数的实现放在.c文件中,主函数放到test.c
函数声明放在函数使用之前,先声明后使用
函数定义是指函数的具体实现,交待函数的功能实现

递归常见的错误:栈溢出(栈空间被耗尽 )

//将无符号整型 一个个输出
void print(int n)
{
        if (n > 9)
        {
               print(n / 10);
        }
        printf("%d ", n % 10);
}
int main()
{
        unsigned int num = 0;
        scanf("%d", &num);
        //递归
        print(num);
}

(1234)
(123)4
(12)3 4
(1)2 3 4

递归直接或间接调用自身的方法,将一个大问题拆成与原问题相似,但规模较小的问题。
递归的两个必要条件:
1、存在限制条件,满足限制条件,递归不在继续;
2、每次递归越来越接近这个限制条件

斐波那契数列(前两数之和等于第三个数)

int count = 0;
int Fib(int n)
{
        if (n == 3)//计算第三个斐波那契数计算次数
        {
               count++;
        }
        if (n <= 2)
               return 1;
        else
               return  Fib(n - 1)+ Fib(n - 2);//1、递归
}

int Fib(int n)
{
        int a = 1;
        int b = 1;
        int c = 1;
        while (n > 2)//2、循环
        {
               c = a + b;
               a = b;
               b = c;
               n--;
        }
        return c;
}
int main()
{
        int n = 0;
        int ret = 0;
        scanf("%d", &n);
        ret = Fib(n);
        printf("%d\n", ret);
}

求字符串长度 strlen
长度不受限制的字符串函数 strcpy strcat strcmp
长度受限制的字符串函数 strncpy strncat strncmp
字符串查找 strstr strtok
错误信息报告 strerror
字符操作
内存操作函数 memcpy memmove memset memcmp

字符串通常放在常量字符串中或者字符数组中

int main()
{
        //int len1 = strlen("abcdef");
        //printf("%d\n", len1);//6
        char arr[] = { 'a','b','c','d','e','f' };
        int len2 = strlen(arr);
        printf("%d\n", len2);//随机值
}

strlen 字符串以\0作为结束标志,返回的是字符串中\0前面出现的字符大小(不包含\0)
函数的返回值是无符号的

int main()
{
        if (strlen("abc") - strlen("abcdef") > 0)
        {
               printf("hehe");//hehe
        }
        else
        {
               printf("haha");
        }
}

返回的值是无符号整型 -3
10000000000000000000000000000011 原码
11111111111111111111111111111100 反码
11111111111111111111111111111101补码>0
无符号整型 补码与原码相同

模拟实现strlen()
1、计数器

int my_strlen(const char* str)//地址要放到指针中,str指针变量
{
        int count = 0;
        assert(str != NULL);//保证指针有效性
        while (*str != '\0')//解引用
        {
               count++;
               str++;
        }
        return count;
}
int main()
{
        char arr[] = "abcdef";
        int len = my_strlen(arr);//数组传参,传过去的不是整个数组,而是数组首元素的地址
        printf("%d\n", len);
}

2、不创建变量实现 递归实现

把大事化小
my_strlen(“bit\0”)
1+my_strlen(“it\0”)
1+1+my_strlen(“t\0”)
1+1+1+my_strlen(“\0”)
1+1+1+0

int my_strlen(const char* str)//str指针变量
{
        
        if (*str != '\0')//*str解引用
        {
               return 1 + my_strlen(str + 1);
        }
        else
        {
               return 0;
        }
}
int main()
{
        char arr[] = "abcdef";
        int len = my_strlen(arr);
        printf("%d\n", len);
}

3、指针实现

int my_strlen(const char* str)//地址要放到指针中,str指针变量
{
    char* start = str;//start指向数组起始地址
    char* end = str;//end指向数组起始地址
    while (*end != '\0')//解引用
    {
        end++;//使end最后一个元素地址 指针+-整数
    }
    return end - start;//指针-指针 指针指向的位置空间相隔几个元素
}
int main()
{
    char arr[] = "abcdef";
    int len = my_strlen(arr);//数组传参,传过去的不是整个数组,而是数组首元素的地址
    printf("%d\n", len);
}

strcpy 源字符串必须以\0结束(防止越界访问),会将源字符串中的\0拷贝到目标空间,目标空间必须足够大,以确保能存放源字符串
模拟实现strcpy()

char* my_strcpy(char* dest, const char* src)//const不改变源字符 char*是指针,返回地址
{
        //指针指向字符串的第一个字符
        //while (*src!='\0')
        //{
        //      *dest++ = *src++;
        //}
        //*dest = *src;//src='\0'
        
        //'\0'的ASCII为0
        //if (dest != NULL && src != NULL)//防止字符串为空
        //{
        //      while (*dest++ = *src++)
        //      {
        //             ;
        //      }
        //}
        char* ret = dest;//将dest的起始地址放到ret中
        assert(dest != NULL);//断言 不满足会报错
        assert(src != NULL);
        while (*dest++ = *src++)//把src指向的字符串拷贝到dest指向的空间,包含'\0'字符
        {
               ;//将\0赋值给*dest=0,结束循环
        }
        return ret;
}
int main()
{
        //strcpy 字符串拷贝
        char arr1[] = "#############";//数组
          char* arr="abcdef";//常量字符串将a的地址放到arr中
        char arr2[] = "bit";
        my_strcpy(arr1, arr2);
        printf("%s\n", arr1);//bit 打印 b i t \0结束标志,后面的#就不打印
}

strncpy()拷贝n个字符从源字符串到目标空间,如果源字符串的长度小于num,则拷贝完字符串后,在目标的后面追加0,直至num个

int main()
{
        char arr1[10] = "abcdef";
        char arr2[] = "hello world";
        strncpy(arr1, arr2, 4);
}

strcat 追加字符串,目标空间必须足够大,不能追加字符串本身 源字符串必须要有\0

int main()
{
        char arr1[30] = "hello";
        char arr2[] = "world";
        strcat(arr1, arr2);
        printf("%s\n", arr1);
}

模拟实现strcat

char* my_strcat(char* dest, char* src)
{
        char* ret = dest;//ret中存储的是目的空间的起始地址
        assert(dest != NULL);
        assert(src);
        //1.找到目的字符串的\0
        while (*dest!='\0')
        {
               dest++;
        }
        //2.追加
        while (*dest++ = *src++)//将src中的元素追加到dest ,src=\0,赋值给dest=0,结束循环
        {
               ;
        }
        return ret;
}
int main()
{
        char arr1[30] = "hello";
        char arr2[] = "world";
        my_strcat(arr1, arr2);
        printf("%s\n", arr1);
}

strncat 指定长度的追加,不管追加几个,在结尾处追加\0,若追加的个数大于源字符串的长度,追加完源字符串后就结束。

int main()
{
        char arr1[30] = "abcdef\0xxxxxxxxxxxxxxxxxxxxxx";
        char arr2[] = "hello world";
        strncat(arr1, arr2, 11);
}

strcmp 一对一对字符比较,比较ASCII值
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串小于第二个字符串,则返回小于0的数字
第一个字符串等于第二个字符串,则返回0

int main()
{
        char* p1 = "abc";
        char* p2 = "pbc";
        //int ret = strcmp(p1, p2);
        //printf("%d\n", ret);
        if (strcmp(p1, p2) > 0)
               printf("p1>p2");
        else if (strcmp(p1, p2) == 0)
               printf("p1=p2");
        else if (strcmp(p1, p2) > 0)
               printf("p1<p2");
}

模拟实现strcmp

int my_strcmp(const char* str1, const char* str2)
{
        assert(str1 && str2);
        //比较
        while (*str1 == *str2)
        {
               if (*str1 == '\0')
               {
                       return 0;//相等
               }
                       str1++;
                       str2++;
        }
        //if (*str1 > *str2)
        //      return 1;//大于
        //else
        //      return -1;//小于
        return (*str1 - *str2);               
}
int main()
{
        char* p1 = "abc";
        char* p2 = "abcd";
        int ret = my_strcmp(p1, p2);
        printf("%d\n", ret);
}

strncmp()字符串比较

int main()
{
        //strncmp字符串比较
        const char* p1 = "abcdef";
        const char* p2 = "abcrty";
        //int ret = strcmp(p1, p2);
        int ret = strncmp(p1, p2, 3);
        printf("%d\n", ret);
}

strstr()查找字符串
返回一个指针指向第一次出现查找字符串的地址,如果找不到返回一个空指针

int main()
{
        char* p1 = "abcedfabcdef";
        char* p2 = "edf";
        char* ret = strstr(p1, p2);//指针变量存放的是地址 strstr返回的是地址
        if (ret == NULL)
        {
               printf("子串不存在\n");
        }
        else
        {
               printf("%s\n", ret);
        }
}

模拟实现strstr()

#include<assert.h>
char* my_strstr(const char* p1, const char* p2)
{
        assert(p1 != NULL);
        assert(p2 != NULL);
        char* s1 = NULL;//初始化
        char* s2 = NULL;
        char* cur = (char *)p1;
        if (*p2=='\0')//p2字符串为空时,指针指向\0的地址
        {
               return (char*)p1;//p1受保护,返回类型不受保护,强制转换
        }
        while (*cur)
        {
               s1 = cur;//cur指向字符串开始位置的地址
               s2 = (char*)p2;
               while (*s1 && *s2 && (*s1 == *s2))//*s1!=\0 *s2!=\0 *s1=*s2
               {
                       s1++;
                       s2++;
               }
               if (*s2 == '\0')
               {
                       return cur;//找到子串
               }
               if (*s1 == '\0')
               {
                       return NULL;//提前终止,找不到子串
               }
               cur++;//cur指向两个字符串字符相等开始的位置
        }
        return NULL;//找不到子串
}
int main()
{
        char* p1 = "abc";
        char* p2 = "abcdedf";
        char* ret = my_strstr(p1, p2);//指针变量存放的是地址 strstr返回的是地址
        if (ret == NULL)
        {
               printf("子串不存在\n");
        }
        else
        {
               printf("%s\n", ret);
        }
}

char strtok (charstr,const char*sep)
sep参数是个字符串,定义了用作分隔符的字符集合
第一个参数指定一个字符串,它包含了0个或多个由sep字符串中一个或多个分隔符分割的标记
strtok函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针 ,第二次指向\0的指针(会改变被操作的字符串,所以切分的字符串一般都是临时拷贝的内容并且可修改 )
strtok函数第一个参数不为NULL,函数将找到str中第一个标记,保存它在字符串中的位置
strtok函数第一个参数为NULL,函数将在同一字符串中被保存的位置开始,查找下一个标记
如果字符串中不存在更多标记,则返回NULL指针

int main()
{
        char arr[] = "zcy@163.com";
        char* p = "@.";
        char buf[1024] = { 0 };
        strcpy(buf, arr);
        //切割buf中的字符串
        char* ret = NULL;
        for (ret = strtok(arr, p); ret != NULL; ret = strtok(NULL, p))//找不到更多标记返回NULL指针,结束循环
        {
               printf("%s\n", ret);
        }
}

strerror返回错误码所对应的错误信息

#include<errno.h>
int main()
{
        //错误码  错误信息
        //0       No error
        //1       Operation not permitted
        //2       No such file or directory
        char* str = strerror(0);
        char* str = strerror(errno);
        //errno是一个全局的错误码变量
        //当c语言的库函数在执行过程中,发生了错误,就会把对应的错误码,赋值到errno中
        printf("%s\n", str);

字符操作
在这里插入图片描述

#include<ctype.h>
int main()
{
        //char ch ='w';
        //int ret = islower(ch);
        //printf("%d\n", ret);
        char ch = '9';
        int ret = isdigit(ch);
        printf("%d\n", ret);
}

字符转换函数 tolower toupper

int main()
{
        //char ch = tolower('A');
        //printf("%c\n", ch);
        char ch = toupper('a');
        putchar(ch);
}
int main()
{
        char arr[] = "I Am A Student";
        int i = 0;
        while (arr[i])
        {
               if (isupper(arr[i]))
               {
                       arr[i] = tolower(arr[i]);
               }
               i++;
        }
        printf("%s\n", arr);
}
int main()
{
        int arr1[] = { 1,2,3,4,5 };
        int arr2[] = { 0 };
        strcpy(arr2, arr1);
}

只拷贝一个1,计算机中小端存放,
01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00
strcpy拷贝字符当把01拷贝下来,拷贝00结束符

memcpy将arr1拷贝到arr2中(任意类型都可以),拷贝num个字节大小
模拟实现memcpy

void* my_memcpy(void* dest, const void* src, size_t num)
{
        void* ret = dest;//dest改变 ret不变
        assert(dest != NULL);
        assert(src != NULL);
        while (num--)//num单位为字节
        {
               *(char*)dest = *(char*)src;//将类型强制转换为char*类型 一次拷贝一个字节
               ++(char*)dest;//由于强制类型转换优先级低于++,但是要先强制类型转换后++
               ++(char*)src;//给(char*)src ++
        }
        return ret;
}
int main()
{
        int arr1[] = { 1,2,3,4,5 };
        int arr2[5] = { 0 };
        my_memcpy(arr2, arr1, sizeof(arr1));
        //strcpy(arr2, arr1);
        struct S arr3[] = { {"zhangsan",20},{"lisi",21} };
        struct S arr4[3] = { 0 };
        my_memcpy(arr4, arr3, sizeof(arr3));
}

memmove处理内存重叠的情况
对于memcpy的要求拷贝不重叠的就可以,但是memcpy可以处理重叠拷贝(不保证所有平台都可以拷贝 )

void* my_memmove(void* dest, const void* src, size_t num)
{
        char* ret = dest;
        assert(dest != NULL);
        assert(src != NULL);
        //if (dest<src || dest>(char*)src + num)
        //{
        //      //从前向后
        //}
        //else
        //{
        //      //从后向前
        //}
        if (dest < src)
        {
               //从前向后
               while (num--)//先使用后-- num=20 num--=19 num=1 num--=0 20次
               {
                       *(char*)dest = *(char*)src;
                       ++(char*)dest;
                       ++(char*)src;
               }
        }
        else
        {
               //从后向前
               while (num--)// num是变量,看num
               //先使用后-- 先使用num=20进循环  后-- num--=19 ,循环内进行运算
               //先使用num=1进循环 后-- num--=0 循环内+的是0
               {
                       *((char*)dest + num) = *((char*)src + num);
               }
        }
        return ret;
}
int main()
{
        int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
        int i = 0;
        //memcpy(arr + 2, arr, 20);
        my_memmove(arr + 2, arr, 20);
        for (i = 0; i < 10; i++)
        {
               printf("%d ", arr[i]);
        }
}

memcpy
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 1,2,5,4,3 };
int ret = memcmp(arr1, arr2, 9);
printf(“%d\n”, ret);
}

memset()将指针空间前num个字节,设置为value

int main()
{
        char arr[] = "hello world";
        memset(arr, '*', 5);
        printf("%s\n", arr);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值