首页 > 其他分享 >【C语言】基础知识详解(二) 字符串

【C语言】基础知识详解(二) 字符串

时间:2024-08-20 12:52:52浏览次数:14  
标签:include dest 基础知识 char 详解 内存 str 字符串 C语言

一、什么是字符串?

在C语言中,字符串是一种特殊的字符数组,用于存储一系列字符。

  1. 字符串的表示:在C语言中,字符串是由字符组成的数组,并以空字符 '\0' 结束。空字符用于标识字符串的结束。例如,字符串 "hello" 在内存中实际上是 {'h', 'e', 'l', 'l', 'o', '\0'}

  2. 字符串声明:可以使用字符数组来声明字符串。例如:

  3. char str[6] = "hello";
    

    注意数组的大小是6,因为包括了字符串的结束符 '\0'

  4. 字符串初始化:可以在声明时直接初始化字符串,也可以通过逐个字符的方式来赋值:

char str1[] = "hello"; // 自动分配足够的空间
char str2[6] = "hello"; // 明确指定数组大小

二、字符串与字符数组 

字符数组是一种存储字符数据的基本数据结构。它们是处理文本数据的核心工具之一。

       1.字符数组的定义: 字符数组是由一组字符元素组成的数组。可以用以下方式声明和初始化字符数组:

char array[10];      // 声明一个可以存储10个字符的数组
char str[] = "hello"; // 声明并初始化一个字符数组,大小自动计算

        2.字符数组的访问: 你可以通过下标来访问字符数组中的每个字符。例如: 

char str[] = "hello";
char first_char = str[0]; // 'h'
char second_char = str[1]; // 'e'

        3.字符数组的大小: 字符数组的大小是固定的,一旦定义不能更改。如果数组的实际大小不足以存储所有需要的字符(包括结束符),会导致缓冲区溢出或未定义行为。正确设置数组的大小是很重要的:

char buffer[20]; // 足够大的缓冲区以存储20个字符

        4.字符串与字符数组的区别:虽然字符串在C中是字符数组的特例,但它们有一些不同之处。字符数组可以容纳任意字符数据,而字符串必须以 '\0' 结束才能正确处理。

三、字符串的常用操作函数

C语言为我们提供了许多操作函数用来处理字符串变量,它们主要集中在 <string.h> 头文件中。下面为大家简单介绍几个常用的操作函数:

1. strcmp

功能: 比较两个字符串。

原型:

int strcmp(const char *str1, const char *str2);

返回值:

  • 0:两个字符串相等。
  • 负数:str1 小于 str2
  • 正数:str1 大于 str2

示例:

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

int main() {
    char str1[] = "apple";
    char str2[] = "banana";
    int result = strcmp(str1, str2);
    if (result < 0) {
        printf("str1 is less than str2\n");
    } else if (result > 0) {
        printf("str1 is greater than str2\n");
    } else {
        printf("str1 is equal to str2\n");
    }
    return 0;
}

 与此函数功能相似的还有strncmp函数:

功能: 比较两个字符串的前 n 个字符。

原型:

int strncmp(const char *str1, const char *str2, size_t n);

参数:

  • str1:第一个字符串。
  • str2:第二个字符串。
  • n:要比较的字符数。

返回值: 与 strcmp 相同,但仅比较前 n 个字符。

2. strcat

功能: 连接两个字符串,将 str2 追加到 str1 的末尾。

原型:

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

参数:

  • dest:目标字符串,必须有足够的空间来存放连接后的结果。
  • src:源字符串。

返回值: dest

示例:

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

int main() {
    char str1[20] = "Hello, ";
    char str2[] = "World!";
    strcat(str1, str2);
    printf("%s\n", str1); // 输出 "Hello, World!"
    return 0;
}

 与此函数功能相似的还有strncat函数:

功能: 将源字符串的前 n 个字符追加到目标字符串的末尾。

原型:

char *strncat(char *dest, const char *src, size_t n);

参数:

  • dest:目标字符串。
  • src:源字符串。
  • n:要追加的字符数。

返回值: dest

示例:

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

int main() {
    char dest[20] = "Hello, ";
    char src[] = "World!";
    strncat(dest, src, 3); // 仅追加 "Wor"
    printf("%s\n", dest); // 输出 "Hello, Wor"
    return 0;
}

3. strcpy

功能: 复制源字符串到目标字符串。

原型:

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

参数:

  • dest:目标字符串,必须有足够的空间来存放源字符串及结束符。
  • src:源字符串。

返回值: dest

示例:

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

int main() {
    char src[] = "Hello, World!";
    char dest[50];
    strcpy(dest, src);
    printf("%s\n", dest); // 输出 "Hello, World!"
    return 0;
}

注意,strcpy函数通常用于字符串赋值。因为在一定场景下对字符串进行赋值时,若使用“=”,只会将原始数据的地址(即一个常量)赋值给目标变量。而使用strcpy函数会使用两个字符串进行拷贝操作,确保了赋值的准确性。

与以上的几个函数一样,也存在strncpy函数可以进行部分拷贝,可以灵活地将字符串给分割。此处不过多赘述。

4. strlen

功能: 计算字符串的长度(不包括结束符 '\0')。

原型:

size_t strlen(const char *str);

参数:

  • str:待计算长度的字符串。

返回值: 字符串的长度。

示例:

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

int main() {
    char str[] = "Hello, World!";
    size_t length = strlen(str);
    printf("Length: %zu\n", length); // 输出 "Length: 13"
    return 0;
}

5. strtok

功能: 分解字符串为一系列标记(tokens),根据分隔符分割。

原型:

char *strtok(char *str, const char *delim);

参数:

  • str:待分解的字符串。第一次调用时传递原始字符串,之后传递 NULL 以获取后续标记。
  • delim:分隔符字符串,包含所有用作分隔的字符。

返回值: 指向当前标记的指针。

示例:

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

int main() {
    char str[] = "Hello, World! How are you?";
    char *token = strtok(str, " ,!?");
    while (token != NULL) {
        printf("%s\n", token);
        token = strtok(NULL, " ,!?");
    }
    return 0;
}

6. strstr

功能: 查找子字符串在主字符串中的第一次出现位置。

原型:

char *strstr(const char *haystack, const char *needle);

参数:

  • haystack:主字符串。
  • needle:要查找的子字符串。

返回值: 指向子字符串在主字符串中的位置;如果未找到,则返回 NULL

示例:

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

int main() {
    char str[] = "Hello, World!";
    char *pos = strstr(str, "World");
    if (pos != NULL) {
        printf("Found substring: %s\n", pos); // 输出 "World!"
    }
    return 0;
}

四、字符串的引申应用

以上所提到的字符串操作函数被引申至内存上,有了一部分内存操作函数,内存操作函数主要集中在 <stdlib.h><string.h> 头文件中。

1. memcpy

功能: 从源内存块复制指定字节数到目标内存块。

原型:

void *memcpy(void *dest, const void *src, size_t n);

参数:

  • dest:目标内存块。
  • src:源内存块。
  • n:要复制的字节数。

返回值: 返回 dest

示例:

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

int main() {
    char src[] = "Hello, World!";
    char dest[20];
    memcpy(dest, src, strlen(src) + 1); // 复制字符串,包括结束符
    printf("%s\n", dest); // 输出 "Hello, World!"
    return 0;
}

2. memmove

功能: 从源内存块移动指定字节数到目标内存块,允许内存重叠。

原型:

void *memmove(void *dest, const void *src, size_t n);

参数:

  • dest:目标内存块。
  • src:源内存块。
  • n:要移动的字节数。

返回值: 返回 dest

示例:

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

int main() {
    char str[] = "abcdefghij";
    memmove(str + 2, str, 5); // 移动前5个字符
    printf("%s\n", str); // 输出 "ababcde"
    return 0;
}

 memcpy与memmove函数的区别:

memcpymemmove 都是用于内存操作的函数,用于复制内存块中的数据,但它们在处理内存重叠情况时有不同的行为。

memcpy 用于从一个内存位置复制数据到另一个内存位置,通常用于内存块之间的简单数据复制。它通常比 memmove 更快,因为它不处理内存重叠的情况。需要注意的是,如果源内存块和目标内存块重叠,memcpy 的行为是未定义的。这可能导致数据丢失或未预期的结果,因此 memcpy 不适用于重叠内存区域。

memmove 适用于处理内存块重叠的情况。在需要将内存中的数据从一个区域移动到另一个区域时,即使这两个区域重叠,memmove 也能安全地处理。memmove 在执行过程中会采取一些措施来处理源和目标区域重叠的情况,从而保证数据的正确性。

因此,选择使用 memcpy 还是 memmove 主要取决于是否需要处理内存区域的重叠。如果确定内存区域不重叠,使用 memcpy 可以获得更好的性能和更高的效率 ;如果内存区域可能重叠,则应该使用 memmove 以确保数据的正确性。

3. memset

功能: 设置内存块的每个字节为指定的值。

原型:

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

参数:

  • ptr:要设置的内存块。
  • value:要设置的值(将被转为无符号字符)。
  • num:要设置的字节数。

返回值: 返回 ptr

示例:

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

int main() {
    char str[20];
    memset(str, '*', sizeof(str) - 1); // 设置所有字节为 '*'
    str[19] = '\0'; // 确保以 null 结束
    printf("%s\n", str); // 输出 "*******************"
    return 0;
}

五、结语

以上就是我对字符串模块基础知识点的一些总结,欢迎小伙伴们在评论区发布讨论,一起交流。

标签:include,dest,基础知识,char,详解,内存,str,字符串,C语言
From: https://blog.csdn.net/weixin_74304436/article/details/141333974

相关文章

  • 学懂C++(三十九):网络编程——深入详解 TCP 和 UDP 的区别和应用场景
    目录一、TCP的特点及应用场景1.可靠性2.流控制和拥塞控制3.有序传输4.应用场景二、UDP的特点及应用场景1.无连接2.不可靠性3.轻量级4.支持广播和多播5.应用场景三、TCP和UDP的区别四、TCP和UDP的工作原理1.TCP的工作原理三次握手数据传输......
  • 学懂C++(四十):网络编程——深入详解 HTTP、HTTPS 及基于 Windows 系统的 C++ 实现
    目录一、引言二、HTTP协议1.HTTP概述2.HTTP工作原理3.HTTP请求和响应格式HTTP请求格式4.HTTP状态码三、HTTPS协议1.HTTPS概述2.HTTPS工作原理四、基于Windows系统的C++实现1.准备工作2.HTTP客户端实现示例代码3.HTTPS客户端实现示例代......
  • 神经网络之卷积篇:详解单层卷积网络(One layer of a convolutional network)
    详解单层卷积网络如何构建卷积神经网络的卷积层,下面来看个例子。已经写了如何通过两个过滤器卷积处理一个三维图像,并输出两个不同的4×4矩阵。假设使用第一个过滤器进行卷积,得到第一个4×4矩阵。使用第二个过滤器进行卷积得到另外一个4×4矩阵。最终各自形成一个卷积神经网络......
  • 新手专科准大一学习c语言的第4天之break、continue的学习
    学习brake        在昨天学习的循环里brake的作用个人明白了如何使条件达到一定值后退出提前终止循环不再按照循环表达式里的条件进行循环。        例如#include<stdio.h>intmain(){inti=1;//声明第一个变量intl=1;//声明第二个......
  • TopoJSON格式详解,写入读取TopoJSON示例
    还是大剑师兰特:曾是美国某知名大学计算机专业研究生,现为航空航海领域高级前端工程师;CSDN知名博主,GIS领域优质创作者,深耕openlayers、leaflet、mapbox、cesium,canvas,webgl,echarts等技术开发,欢迎加底部微信(gis-dajianshi),一起交流。No.内容链接1Openlayers【入门教程】-......
  • 【Laravel 】faker数据填充详解
    【Laravel】faker数据填充详解 安装在laravel中已经自动集成,无需手动安装。如需在其他地方使用,可使用以下命令进行安装。composerrequirefzaninotto/faker为Faker指定中文支持可通过在 config/app.php 增加如下配置使其支持中文:'faker_locale'=>'zh_CN',基......
  • 数据结构day01(数据结构、算法基础知识)
    目录【1】数据结构基础知识1》什么是数据结构2》数据 3》逻辑结构1>线性关系2>层次关系3>网状关系4》存储结构  1>顺序存储 2>链式存储3>索引存储结构 4>散列存储 5》操作【2】算法基础知识1>什么是算法 2>算法设计 3>算法的特性 4>评价算法的......
  • 正则表达式入门:Python ‘ re ‘ 模块详解
    正则表达式(RegularExpression,简称re)是一种强大而灵活的工具,广泛用于字符串匹配、替换和分割等操作,尤其在处理网页爬虫数据时非常有用。Python提供了"re" 模块来支持正则表达式的使用,本文将结合常见的用法和示例,带你快速入门。正则表达式的常用方法匹配字符串1.'sea......
  • C语言:一维、二维数组详解
    目录一、数组的概念二、一维数组创建和初始化2.1数组创建2.2数组的初始化2.3数组的类型三、一维数组的使用3.1数组的下标3.2数组的输入与输出四、⼀维数组在内存中的存储五、sizeof计算数组元素个数六、二维数组6.1二维数组的概念6.2二维数组的创建6.3二......
  • C语言 函数
    数组概念C语言中得函数就是一个完成某项特定的任务的一小段代码。这段代码是有特殊的写法和调试方式的。C语言的程序是由无数个小的函数组成的C语言中我们会用到两种函数:库函数自定义函数库函数1.标准库和头文件C语言中是不会提供任何函数的,C语言的国际标准(ANSIC)规定了......