首页 > 其他分享 >【C语言】字符串与相关操作函数

【C语言】字符串与相关操作函数

时间:2024-07-12 23:02:26浏览次数:26  
标签:函数 dest C语言 char 内存 字符串 sizeof

字符串


思路分析在注释

文章目录


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

一、字符串的定义

  • 字符串是由字符数组表示的,并且以空字符 ‘\0’ 结尾。
  • 字符串的结尾由空字符 ‘\0’ 标识,这个字符用来表示字符串的终止。因此,字符串的实际长度比可见字符的数量多一个。

在C语言中,字符串可以用字符数组或字符指针来定义

// 字符数组---字符串变量
char str[ ] = {'h','e','l','l','0'};
char str1[] = "Hello"; // 实际上是 {'H', 'e', 'l', 'l', 'o', '\0'}

// 字符指针---字符串常量
char *str2 = "Hello, World!";

内存分配:使用字符指针定义的字符串是只读的,如果需要修改字符串的内容,应该使用字符数组。

数组越界:操作字符串时要注意数组越界的问题,确保数组有足够的空间来存储字符串及其终止符 '\0'.

1. 使用sizeof()计算他们的长度

#include <stdio.h>

int main()
{
    char str[] = {'h','e','l','l','o'};
    char str1[] = "hello";

    int len = sizeof(str)/sizeof(str[0]);
    printf("str的长度%d\n",len);
    len = sizeof(str1)/sizeof(str1[0]);
    printf("str1的长度%d\n",len);

    return 0;
}

运行结果
在这里插入图片描述
使用字符数组初始化(char str[] = {'h', 'e', 'l', 'l', 'o'})时,数组的长度仅包括实际字符的数量,不包括空字符。

使用字符串字面量初始化(char str1[] = "hello")时,数组的长度包括字符串结束符 \0。


二、sizeof和strlen的区别

sizeof 和 strlen 是在C语言中用来处理数组和字符串的两个常用函数(或运算符),它们的功能和用途有显著区别

1.sizeof 操作符

  • sizeof 是一个编译时运算符,用于计算变量、数据类型或表达式的大小(以字节为单位)。它可以用来计算任何数据类型的大小,包括基本类型(如int, char, float 等),结构体,数组等

2.strlen 函数

  • strlen 是一个在 <string.h> 头文件中定义的库函数,用于计算以空字符(\0)结尾的字符串的长度(不包括空字符)。它只能用于 char 类型的字符串数组字符串指针

代码如下(示例)

#include <stdio.h>
#include <string.h>

void test()
{
}
int main()
{
    char str[] = "hello";// '\0'
    void (*ptest)();
    ptest = test;
    printf("sizeof(str) :%d\n", sizeof(str)); // 6
    printf("strlen(str) :%d\n", strlen(str)); // 5

    char *p = "hello";
    //p是一个char*类型,指向一个字符串,字符串以'\0'结束 sizeof来计算的时候,是计算指针的大小,而不是字符串的大小
    printf("sizeof(p) :%d\n", sizeof(p));          // 8
    printf("sizeof(char*) :%d\n", sizeof(char *)); // 8
    printf("strlen(char) :%d\n", sizeof(char));    // 1
    printf("strlen(int*) :%d\n", sizeof(int*));    // 8
    printf("strlen(ptest) :%d\n", sizeof(ptest));  // 8
    printf("strlen(p) :%d\n", strlen(p));          // 5

    return 0;
}

三、动态开辟字符串

1.malloc函数

malloc 是 C 标准库中的一个函数,用于动态分配内存(在堆区)。它声明在 <stdlib.h> 头文件中。malloc 的全称是 “memory allocation”,其原型为

void *malloc(size_t size);

参数:

  • size_t size:这是一个无符号整数类型,用于指定要分配的内存大小,以字节为单位。

返回值:

  • malloc 返回一个 void * 类型的指针,指向已分配内存块的起始地址。
  • 如果内存分配成功,返回值是一个非 NULL 的指针。
  • 如果内存分配失败(例如系统没有足够的内存),返回值是 NULL。

注意:
使用 malloc 分配的内存需要手动释放(使用 free 函数),否则可能会导致内存泄漏。
始终检查 malloc 的返回值,以确保内存分配成功

2.realloc函数

realloc函数用于调整之前通过malloc或calloc分配的内存块的大小。它可以扩大或缩小内存块,并且可以保留原始内存块中的数据(如果内存被扩大,新的内存块可能会位于不同的位置)。如果新大小比原大小大,扩展部分的内容是未定义的,其原型为

void *realloc(void *ptr, size_t size);

参数

  • ptr:指向要调整大小的内存块的指针。如果ptr为NULL,realloc的行为就像malloc一样
  • size:新的内存块大小(以字节为单位)

返回值

  • 返回一个指向新内存块的指针。如果失败,返回NULL,并且原内存块保持不变

3. free函数

free函数用于释放之前通过malloc、calloc或realloc分配的内存块。它将内存返回给系统,使得这些内存可以被重新分配。释放内存是防止内存泄漏的重要步骤,因为如果程序持续分配内存而不释放,将会耗尽可用内存,最终导致程序或系统崩溃。

void free(void *ptr);

参数

  • ptr:指向要释放的内存块的指针。如果ptr为NULL,free什么也不做

4. memset函数

memset函数用于将指定的值设置为指定内存块的每个字节。这通常用于初始化内存,例如将数组中的所有元素设置为0或某个特定的值

void *memset(void *ptr, int value, size_t num);

参数

  • ptr:指向要填充的内存块的指针。
  • value:要设置的值,以整数形式传递,但会被转换为无符号字符。
  • num:要设置的字节数。

返回值

  • memset返回指向内存块的指针

使用示例

#include <stdio.h>
#include <string.h>
#include <stdlib.h>


int main()
{
    char *p; //野指针
    p = (char*)malloc(2);//分配内存,p有了具体的内存指向
    *p = 'a';
    *(p + 1) = '\0'; // 添加空终止符 puts(p)期望一个以空字符('\0')结尾的字符串,puts会继续读取超出你分配的内存,这会导致未定义行为,可能打印出一些垃圾值。
    puts(p);
    free(p);//执行后p又是野指针
    p = (char*)malloc(12);
    memset(p,'\0',12);
    printf("扩容地址:%x\n",p);
    int len = strlen("hello world12324242");
    int new_len = len - 12 + 1;
    realloc(p,new_len);
    printf("扩容后的地址:%x\n",p);
    strcpy(p,"hello world12324242");
    printf("%s\n",p);
    free(p);
    return 0;
}

四、几种字符串常用的API

1. strncpy函数

strncpy函数用于将字符串从源复制到目标,但最多复制n个字符。如果源字符串长度小于n,目标字符串的剩余部分将用空字符填充。

参数

  • dest:指向目标字符串的指针
  • src:指向源字符串的指针
  • n:要复制的最大字符数。
    返回值
  • 返回目标字符串的指针(dest)

strncpy的行为

  • 如果src的长度小于n,dest的剩余部分将用空字符填充。
  • 如果src的长度大于或等于n,strncpy不会在dest的末尾添加空字符。
    代码示例
#include <stdio.h>
#include <string.h>

int main() {
    char src[] = "hi";
    char dest[10];

    strncpy(dest, src, 10); // 复制源字符串到目标,最多10个字符
    printf("dest: %s\n", dest); // 输出: dest: hi(后面跟随一些空字符)

    return 0;
}

自己编写strncpy函数,实现相似功能

#include <stdio.h>

char* my_strncpy(char *dest,char *src, int count)
{
    char *p = dest;
    while(*src != '\0' && count>0)
    {
        *dest++ = *src++;
        count--;
    }
    if (count>0)
    {
        while(count--)
        {
            *dest++ = '\0';
        }
        return p;
    }
    *dest = '\0';

    return p;
}
int main() {
    
    char a[50]="\0";
    char *p = "nihao";
    char *pchar = my_strncpy(a, p, 10);
    puts(pchar);
    puts(a);
    return 0;
}

2. assert函数

assert函数用于在程序运行时进行断言检查,即在调试阶段检查程序中的某些假设是否成立。如果断言失败,程序将输出一条错误信息并终止运行。它是帮助开发人员在调试阶段发现和修复错误的有力工具。

//函数原型
void assert(int expression);

参数

  • expression:一个整数表达式。当表达式为假(即值为0)时,assert会触发一个断言失败的错误。

3. strcat函数

strcat 是 C 标准库中的一个函数,用于将一个字符串追加到另一个字符串的末尾。它声明在 <string.h> 头文件中。strcat的原型为

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

参数

  • char *dest:指向目标字符串的指针,该字符串必须有足够的空间容纳源字符串和原目标字符串的内容。
  • const char *src:指向源字符串的指针,该字符串的内容将被追加到目标字符串的末尾。

返回值:

  • 返回值是指向目标字符串 dest 的指针

代码示例

自己编写strcat函数,实现相似功能(使用两种方式)

char* my_strcat(char *dest,char *src)
{
    assert(dest != NULL && src != NULL);

    char *p = dest;
    while(*dest != '\0')
    {
        *dest++;
    }
    while((*dest++ = *src++) != '\0')
   
    *dest = '\0';

    return p;
}
char* my_strcat1(char *dest,char *src)
{
    assert(dest != NULL && src != NULL);

    char *p = dest;
    strcpy(dest+strlen(dest),src);

    return p;
}
int main() {
    
    char *pchar;
    char a[50]="nihao";
    char *p = "xiaoming";
    //pchar = strcat(a,p);
    pchar = my_strcat1(a,p);
    puts(pchar);
    puts(a);
    return 0;
}

把src所指向的字符串(包括“\0”)复制到dest所指向的字符串后面(删除*dest原来末尾的“\0”)。要保证*dest足够长,以容纳被复制进来的*src。*src中原有的字符不变。返回指向dest的指针。

标签:函数,dest,C语言,char,内存,字符串,sizeof
From: https://blog.csdn.net/qq_40064717/article/details/140290099

相关文章

  • C语言-分支与循环(1)
    目录1、if语句1.1if1.2else1.3分支中包含多条语句1.4嵌套if1.5悬空else问题(多个if和一个else对应关系)2、switch语句2.1switch语句中的break2.2switch语句中的default2.3switch语句中的case和default的顺序问题3、关系操作符4、条件操作符4.1什么是条件......
  • 实验9 存储过程与函数的创建管理实验
    一、实验目的:理解存储过程和函数的概念。掌握创建存储过程和函数的方法。掌握执行存储过程和函数的方法。掌握游标的定义、使用方法。二、实验内容1.某超市的食品管理的数据库的Food表,Food表的定义如表所示,Food表的定义各列有如下数据:‘QQ饼干’,‘QQ饼干厂’,2.5,‘2......
  • 实现猜数字游戏(C语言)
    简单版本#include<stdio.h>#include<stdlib.h>#include<time.h>#include<Windows.h>#include<string.h>voidmenu(){ chararr[]="************************"; chararr1[]="--Welcometomygame!!--"; int......
  • 学习C语言第一天
    今天看了B站上的几节课,总结了以下几个要点:1.githud,码云两个网站实现代码托管,坚持上传代码。2.CSDN坚持写博客,善于总结包括xmind。3.不做伸手党,要学会自己解决问题。4.操作系统,计算机网络+网络编程,比较难,上课要认真,还需要看书补偿。5.数据结构要听懂。6.介绍了课程安排。7.了解......
  • c语言的简易教法—— 函数递归
    文章目录一、什么是递归?1.1递归的思想1.2递归的限制条件二、递归案例2.1案例1:求n的阶层2.1.1分析2.1.2递归函数(Fact)的代码实现2.1.3测试:main函数实现2.1.4运行结果和画图推演2.1.5扩展:迭代方法求解n的阶乘2.2案例2:顺序打印⼀个整数的每⼀位2.2.1分析2.2.2打印数(p......
  • 如何在函数中使用return返回axios的请求结果
    使用场景:在添加学生上课记录的时候,需要先获取学生的剩余课时,需要通过接口获取。所以需要封装一个方法,能够通过接口获取学生的课时数量。解决方案:通过异步解决封装方法的代码如下:constgetStudentCourseCount=async()=>{letnum=0awaitaxios({method:......
  • 10个Python函数参数进阶用法及代码优化
    目录1.默认参数值:让函数更加灵活2.关键字参数:清晰的调用方式3.*args:拥抱不确定数量的位置参数4.**kwargs:处理不确定数量的关键字参数5.参数解包:简化多参数的传递6.命名关键字参数:限制关键字参数7.局部变量与全局变量:理解作用域8.高级:装饰器(@decorator)9.Lambd......
  • python每日学习4:函数的定义和各类参数定义与用法
    目录目录一、函数的定义二、参数的定义和用法1、必选参数2、默认参数3、可变参数4、关键字参数5、命名关键字参数三、参数在实际操作中的要求一、函数的定义1、函数代码块以def关键词开头,后接函数名称和圆括号()2、在圆括号内定义传入参数3、函数的第一行语句可以......
  • 我的MYSQL学习心得, 自定义存储过程和函数
    转载:https://www.cnblogs.com/lyhabc/p/3793524.html我的MYSQL学习心得(一)简单语法我的MYSQL学习心得(二)数据类型宽度我的MYSQL学习心得(三)查看字段长度我的MYSQL学习心得(四)数据类型我的MYSQL学习心得(五)运算符我的MYSQL学习心得(六)函数我的MYSQL学习心得(七)查询我的MYSQ......
  • 动态添加HTML时onclick函数参数传递
    onclick函数动态传参1.参数为数值类型时:var tmp=123;var strHTML="<divonclick=func(" +tmp+")>点击弹出数据及其类型</div>";info.append(strHTML); function func(tmp){    alert(typeof tmp+"" +tmp);}string12......