【C语言基础】:字符串函数(二)

简介: 【C语言基础】:字符串函数(二)

上节回顾:【C语言基础】:字符函数和字符串函数

一、strncpy函数的使用

函数原型:

char * strncpy ( char * destination, const char * source, size_t num );
• 1

strncpy与strcpy的区别:

从函数的参数来看,strncpy和strcpy前面几个参数都是char * destination, const char * source,也就是将source的内容拷贝到destination里面去,但是strncpy函数多了一个参数size_t num,也就是对拷贝的内容有了数量上的限制,而strcpy则对拷贝的内容没有数量上的限制。


从字符串中复制字符

将源的第一个num字符复制到目标。如果在复制num个字符之前找到源C字符串的结尾(用空字符表示),则目的地将用零填充,直到向其写入总数为num个字符。


如果source大于num,则不会在destination的末尾隐式添加空字符。因此,在这种情况下,destination不应被视为以空结束的C字符串(这样读取会溢出)。


【strncpy的使用】

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

int main()
{
  char arr1[] = "abcdef";
  char arr2[20] = { 0 };
  strncpy(arr2, arr1, 3);
  printf("%s\n", arr2);
  return 0;
}

b633bef80c86dade1447ca865f0a9ca1_12aca65308f448d5acabfed7c7b58615.png

使用strncpy的注意事项:


1.是否将 \0拷贝

首先我们要知道将arr1中的内容拷贝到arr2中,那是否会将arr1中的 \0也拷贝到arr2中呢?其实要验证这一点很简单,我们将arr2中的内容改成xxxxxxxxxxxx,然后再拷贝调试看一下。

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

int main()
{
  char arr1[] = "abcdef";
  char arr2[20] = "xxxxxxxxxxxx";
  strncpy(arr2, arr1, 3);
  printf("%s\n", arr2);
  return 0;
}

92703e1ae7774f04af8f77f7f32bcbd3_683ed03aef564db6a3e8f0a6406751f8.png

64f2620764af7a214f6e5d93f7e5f1cf_fd4b77a039e14a7fa433ab0310d1f42c.png


在调试的时候可以看到,strncpy并没有将 \0给拷贝过去,另外我们运行之后可以看到打印之后把abc之后的x也打印出来了,如果 \0也拷过来的话,那么用\s打印的话遇到 \0就会停止打印。


2.拷贝数量大于原字符数量

在使用strncpy时如果原字符串的数量小于要求拷贝的数量会怎么样呢?arr1中有abcdef六个字符,那如果要求拷贝10个字符该怎么办呢?我们还是来调试看一下。

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

int main()
{
  char arr1[] = "abcdef";
  char arr2[20] = "xxxxxxxxxxxxxxx";
  strncpy(arr2, arr1, 10);
  printf("%s\n", arr2);
  return 0;
}


调试之后可以看到,但原字符串数量不够时,会用 \0来补充,不够10位就用 \0来不够10位。用/s打印到 \0就会停止,后面即使有内容也不会打印。


二、strncat函数的使用

函数原型:

char * strncat ( char * destination, const char * source, size_t num );

从字符串中添加字符

将源的第一个num字符附加到目标,加上一个结束的空字符。

如果source中的C字符串的长度小于num,则只复制结束空字符之前的内容。


和上面的类似strncat和strcat的区别也是在于strncat函数多了一个size_t num的参数。


【strncat的使用】


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

int main()
{
  char arr1[] = "abcdef";
  char arr2[20] = "xx";
  strncat(arr2, arr1, 3);
  printf("%s\n", arr2);
  return 0;
}

b5fe839463949cd47d4fc2a08dcbc498_800abb08a93c461aa797141e05730a0c.png

注意事项:


1.是否追加 \0

这里因为arr2的xx后面都是 \0,追加之后无法看出是否将 \0也追加了进来,但我们知道strcar是从 \0开始追加的,这里我们让他提前追加就行了。

686bd455adb122f1e0e4d10bd2a5ff7b_4216962f39dd44838c1e425a4e9926ff.png

可以看到,strncat会将 \0也追加进来。

2.追加字符数量大于原字符

65281d5b0f094fc0646571441293af60_d9e33722925044e398013d8a0179301f.png

调试之后可以看到,如果追加的数量大于原字符数量,那么将 \0追加完追后就不会继续追加了。

三、strncmp函数的使用

函数原型:

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

比较两个字符串的字符

比较C字符串str1和C字符串str2的最多num个字符。

这个函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续执行后面的对,直到字符不相同,直到达到终止的空字符,或者直到两个字符串中的num字符匹配,以先发生的为准。




【strncmp函数的使用】


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

int main()
{
  char arr1[] = "abcdef";
  char arr2[] = "abqdefgui";
  int ret = strncmp(arr1, arr2, 3);
  printf("%d\n", ret);
  return 0;
}

4a5ac9d22ff75ee7f731cc126d3e4542_1b6b9647a7864efda023fe6bf22a2290.png

第三个参数就是最多比较的次数,如果在这之前就比较出了结果,那么后面的也将不会再比较。


四、strstr函数的使用和模拟实现

函数原型:

char * strstr ( const char * str1, const char * str2 );

查找子字符串

返回指向str1中str2第一次出现的指针,如果str2不是str1的一部分,则返回空指针。

匹配过程不包括结束的空字符,但它到此为止。

字符串的比较匹配不包含 \0 字符,以 \0 作为结束标志


4.1 strstr函数的使用

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

int main()
{
  char arr1[] = "this is an apple\n";
  const char arr2[] = "is";
  char arr3[] = "pa";
  char* p = strstr(arr1, arr2);
  char* pa = strstr(arr1, arr3);
  printf("%s\n", p);
  printf("%s\n", pa);
  return 0;
}

0593fdd11de6e52944aa366745174bb7_648c225d9e0e4dea881276a45819f7d3.png

返回arr2在arr1中第一次出现的指针,如果没有匹配到,就返回空指针。


4.2 strstr函数的模拟实现

模拟实现的函数参数类型以及返回类型:从原函数可以看出,参数是接收的arr1和arr2数组首元素的地址,也就是char* 类型的,我们只是用来进行比较匹配,为了防止被修改,参数前面都要加const进行修改。原函数的返回类型是arr2在arr1中第一次出现的指针,所以返回类型就是 char*。


char* my_strstr(const char* str1, const char* str2)
{

}

模拟分析:


第一种情况:

str1:abcdef\0

str2:bcd\0


这里arr1从b开始匹配一次就能匹配成功,当str2的指针指向\0时,就说明已经匹配到了,但需要有一个指针记录从哪里开始匹配的。


第二种情况:

str1:abbbcdef\0

str2:bbc\0


这种情况就比较复杂,当str1中的第一个b和str2中的b匹配时,str2中的第一个和第二个都能匹配上,当第三个str2是c,而str1却是b,这时候又要回去重新进行匹配,但str2中的指针已经指向c了,没办法回去,所以这里不仅需要一个指针记录开始匹配的位置,还需要一个指针指向str2的开始位置,方便那个指针能指向回来。


第三种情况:

str1:abcdef\0

str2:bbq\0


这种情况最简单,就是匹配不到。


#include<stdio.h>

char* my_strstr(const char* str1, const char* str2)
{
  const char* s1 = NULL;
  const char* s2 = NULL;
  const char* cur = str1;
  if (*str2 == '\0')
    return (char*)str1;
  while (*cur)
  {
    s1 = cur;
    s2 = str2;
    while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
    {
      s1++;
      s2++;
    }
    if (*s2 == '\0')  // 匹配完成
    {
      return (char*)cur;
    }
    cur++;
  }
  return NULL;  // 没找到
}

int main()
{
  char arr1[] = "this is an apple\n";
  const char arr2[] = "is";
  char arr3[] = "pa";
  char* p = my_strstr(arr1, arr2);
  char* pa = my_strstr(arr1, arr3);
  printf("%s\n", p);
  printf("%s\n", pa);
  return 0;
}

70f270e4ab134d6a4f9f43e113609e79_06e7bf63c1d94834bd2aa659a80f4ee3.png


五、strtok函数的使用

函数原型:

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

【strtok函数的使用】

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

int main()
{
  char arr1[] = "zhangxu@qq.com";
  char arr2[30] = { 0 };
  strcpy(arr2, arr1);
  const char* sep = "@.";
  char* ret = NULL;
  for (ret = strtok(arr2, sep); ret != NULL; ret = strtok(NULL, sep))
  {
    printf("%s\n", ret);
  }
  // ret = strtok(arr2, sep);
  // printf("%s\n", ret);

  // ret = strtok(NULL, sep);
  // printf("%s\n", ret);

  // ret = strtok(NULL, sep);
  // printf("%s\n", ret);
  return 0;
}

7b2b4ad4078b0064480c821025ef064e_8680c18e687141e781a4c0d48dfc9f67.png


六、strerror函数的使用

函数原型:

char * strerror ( int errnum );

strerror 函数可以把参数部分错误码对应的错误信息的字符串地址返回来。

在不同的系统和C语⾔标准库的实现中都规定了一些错误码,⼀般是放在 errno.h 这个头⽂件中说明

的,C语言程序启动的时候就会使用一个全局的变量errno来记录程序的当前错误码,只不过程序启动

的时候errno是0,表示没有错误,当我们在使用标准库中的函数的时候发生了某种错误,就会将对应

的错误码,存放在errno中,而一个错误码的数字是整数很难理解是什么意思,所以每⼀个错误码都是

有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回。


【strerror函数的使用】

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

int main()
{
  for (int i = 0; i <= 10; i++)
  {
    printf("%d:\t%s\n", i, strerror(i));
  }
  return 0;
}

9e0ef30d050c6bdd37cc72a0d22c41eb_b940f2a6c7374848af04d3927470bba2.png


举例:


#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
  FILE* pFile;
  pFile = fopen("unexist.ent", "r");
  if (pFile == NULL)
    printf("Error opening file unexist.ent: %s\n", strerror(errno));
  return 0;
}

353d5ce34c3f29902d40348144e313cc_ac8302a8fa5148648c0976a2d3eea076.png

相关文章
|
3月前
|
C语言 C++
【C语言】解决不同场景字符串问题:巧妙运用字符串函数
【C语言】解决不同场景字符串问题:巧妙运用字符串函数
|
3月前
|
存储 C语言
【c语言】字符串函数和内存函数
本文介绍了C语言中常用的字符串函数和内存函数,包括`strlen`、`strcpy`、`strcat`、`strcmp`、`strstr`、`strncpy`、`strncat`、`strncmp`、`strtok`、`memcpy`、`memmove`和`memset`等函数的使用方法及模拟实现。文章详细讲解了每个函数的功能、参数、返回值,并提供了具体的代码示例,帮助读者更好地理解和掌握这些函数的应用。
43 0
|
3月前
|
存储 安全 编译器
深入C语言库:字符与字符串函数模拟实现
深入C语言库:字符与字符串函数模拟实现
|
3月前
|
C语言
C语言常见字符函数和字符串函数精讲
C语言常见字符函数和字符串函数精讲
|
3月前
|
C语言
【C语言】模拟实现深入了解:字符串函数
【C语言】模拟实现深入了解:字符串函数
|
5月前
|
安全 程序员 C语言
【C语言】字符串函数及其模拟实现
【C语言】字符串函数及其模拟实现
|
5月前
|
C语言
【C语言篇】字符和字符串以及内存函数详细介绍与模拟实现(下篇)
perror函数打印完参数部分的字符串后,再打印⼀个冒号和⼀个空格,再打印错误信息。
69 0
|
5月前
|
存储 安全 编译器
【C语言篇】字符和字符串以及内存函数的详细介绍与模拟实现(上篇)
当然可以用scanf和printf输入输出,这里在之前【C语言篇】scanf和printf万字超详细介绍(基本加拓展用法)已经讲过了,这里就不再赘述,主要介绍只针对字符的函数.
61 0
|
6月前
|
存储 缓存 C语言
【C语言】字符函数,字符串函数,内存函数
C语言中的字符串函数和内存函数
84 0
【C语言】字符函数,字符串函数,内存函数
|
7月前
|
C语言
【c语言】字符串函数的模拟实现(二)
【c语言】字符串函数的模拟实现(二)
31 1