C语言之字符串函数一

简介: C语言之字符串函数一

C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串或字符数组中,字符串常量适用于那些对它不做修改的字符串函数

求字符串长度:

1:strlen函数:size_t strlen(const char*str)【size_t=unsigned int】

举例:

#include<stdio.h>
#include<string.h>
int main()
{
  int len = strlen("hello,C");
  printf("%d\n", len);
  return 0;
}

字符串已经’\0’作为结束标志,strlen函数返回的是在字符串中’\0’前面出现的字符个数(不包含‘\0’),因此输出结果为6

6

但如果我们将其换一种写法,输出结果还会是6吗?

#include<stdio.h>
#include<string.h>
int main()
{
  char arr[] = { 'h','e','l','l','o','C' };
  int len = strlen(arr);
  printf("%d\n", len);
  return 0;
}

**参数指向的字符串必须要以’\0’结束。

74

输出结果为什么是74呢?原因为,此时的hello,C,被我们存放在了字符数组而不是字符串,而字符数组并不包含’\0‘,但strlen函数只有遇到’\0’会停止计算长度,因此这种情况下,strlen函数会在随机值中继续查找,直到碰到’\0’,才会输出长度。

strlen函数返回的类型是size_t(unsigned int)

证明如下:

对上述示例中的stlen函数的返回值类型,我们进行了调整。

左边输出结果为hehe,原因:由于strlen函数的返回值类型是size_t(unsigned int),因此即使字符串”abc"和字符串“abcdef”相减,都不会返回-3,系统会将-3进行,按无符号整数输出。

右边的strlen函数的返回值类型是int,是有符号整数,因此函数返回值为-3.


2:使用指针:

#include<stdio.h>
#include<assert.h>
int my_strlen(const char* str)//const修饰指针char*
//由于要求的字符串是常量字符串,因此指针指向的内容无法被改变
{
  assert(str != NULL);assert(断言):如果出现括号中的情况,则程序会停止运行
  int count = 0;
  while (*str != 0)
  {
    count++;
    str++;
  }
  return count;
}
int main()
{
  char arr[] =("abcdef");
  int my_strlens = my_strlen(arr);
  printf("%d\n", my_strlens); 
}
6

注意:strlen函数的返回值是无符号整数,因此不会出现负数。

证明如下:

#include<stdio.h>
#include<string.h>
int main()
{
  if ((strlen("abc") - strlen("abcdef")) > 0)
    printf("hehe");fan
  else
    printf("haha");
}
hehe

长度不受限制的字符串函数:strcpy/strcat/strcmp

strcpy:char* strcpy(destination,resource)

举例:

#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcpy(char* dest,const  char* res)//做字符串拷贝时,源头字符串不会发生改变变,可以用const修饰
{
  assert(dest != NULL);
  assert(res != NULL);
  char* ret = dest;//定义指针ret,指向dest
  while (*dest++ = *res++)//遇到'\0',循环终止
  {
    ;
  }
  return ret;//注意:这里不能直接返回dest,因此此时的dest已经不是目地空间的起始地址了
}
int main()
{
  char arr1[] = "早上好呀";
  char arr2[] = "小懒虫";
  strcpy_s(arr1, arr2);
  my_strcpy(arr1,arr2);
  printf("%s\n", arr1);
  return 0;
}
小懒虫

注意:*dest++ = res++,运算符和++都属于单目运算符,两者的优先级是一样的,结合性的方向是从右到左。

因此,有些小伙伴会认为这个表达式的运算顺序是:dest/res先自身+1,其次进行解引用,其实这种想法是错误的。

正确的运算顺序应该是:首先解引用指针变量dest/res,然后dest/res再自身加1,之所以不按照从右向左的结合性,是因为++自身的特性引起的。


使用strcpy函数时,需要注意的事项:

1:源字符串必须以’\0’结束

举例:

char arr[] = { 'h','e','l','l','o' };

如果源字符串是上述这种不包含’\0’的,编译器会一直往后找’\0’,因此很有可能b发生越界访问。

2:会将源字符串中的’\0’拷贝到目标空间

举例:

char arr[] = "bit";

arr其实有四个字符,其中还包含’\0’.

3:目标空间必须足够大,以确保源字符串能够完整放入

举例:

char arr[] = "bit";
char arr1[] = "hello,world";

如果是将arr1放入arr中,是不能实现的,因为arr只能存放4个字符,而arr1有12个字符

4:目标空间必须可变

char *p = "hello,world";

如果目标空间是如上所示这种,是无法将其它字符串拷入其中,因为此时p指向的是常量字符串,其无法被改变,如果强制性被改变,会导致程序崩溃。

strcat:

目标空间必须足够大:

举例:

#include<stdio.h>
#include<string.h>
int main()
{
  char arr1[] = "hello";
  char arr2[] = "world";
  strcat_s(arr1, arr2);
  printf("%s\n", arr1);
  return 0;
}

如上所示代码:由于arr1的空间不够大,只能存放6个字符,因此将arr2拷贝到arr1的过程,会导致程序崩溃。

通过调试验证源字符串中的”\0‘也被拷贝过去了


使用strcat函数时,需要注意的事项:

1:源字符串必须以’\0’结束

2:目标空间必须足够大

3:目标空间必须可修改

以上三点,具体证明结果可参考上面的strcpy函数

4:字符串自己追加自己


证明如下:

#include<stdio.h>
#include<assert.h>
char* my_strcat(char* dest,const char* res)
{
  assert(*dest!=NULL);
  assert(res);
  char* ret = dest;
  //先找目标字符串的结束标志
  while (*dest != '\0')
  {
    dest++;
  }
  //字符串自己进行追加
  while (*dest++ = *res++)
  {
    ;
  }
  return ret;//不能直接返回dest,因为此时的dest并不是目标空间的首地址
}
int main()
{
  char arr1[30] = "hello";
  char arr2[] = "world";
  my_strcat(arr1, arr2);
  printf("%s ", arr1);
  return 0;
}
helloworld

通如下路径,我们可以查找各种库函数的实现方法:

strcmp:int strcmp(const charstr1,const charstr2)

举例:

#include<stdio.h>
#include<string.h>
int main()
{
  char arr1[] = "abcdef";
  char arr2[] = "bbc";
  //如果str1>str2,返回大于零的数字,str1<str2返回小于零的数字,二者相等返回0
  int ret=strcmp(arr1, arr2);
  printf("%d ", ret);
  return 0;
}

为什么输出结果是-1呢?如果strcmp比较的是字符串的长度,输出结果应该为大于0的数字

-1

由此我们可以得到结论:strcmp函数在比较字符串的时候,实际比较的是首元素的ASCII码值,如果首元素ASCII码相等,则依次比较第二个第三个,直到不相等。


标准规定: 如果str1>str2,返回大于零的数,str1<str2返回小于零的数,二者相等返回0

在VS编译器下,如果str1>str2,返回1,str1<str2返回-1,二者相等返回0

而在Linux-gcc系统下,strcmp函数返回的是ASCII的差值


因此在使用strcmp函数的时候,不能将函数的返回值设置为具有局限的:


举例:

#include<stdio.h>
#include<string.h>
int main()
{
  char arr1[] = "abcdef";
  char arr2[] = "bbc";
  //1,-1,0只是在VS编译器下,strcmpy函数返回的结果,但C语言并为这样定义
  if (strcmp(arr1, arr2) == 1)
  {
    printf("str1>str2");
  }
  else if (strcmp(arr1, arr2) == 0)
  {
    printf("str1=str2");
  }
  else if (strcmp(arr1, arr2) == -1)
  {
    printf("str1<str2");
  }
  return 0;
}

正确写法:

if (strcmp(arr1, arr2)>0)
  {
    printf("str1>str2");
  }
  else if (strcmp(arr1, arr2) == 0)
  {
    printf("str1=str2");
  }
  else if (strcmp(arr1, arr2) <0)
  {
    printf("str1<str2");
  }

用库函数定义的方法进行实现:

#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_strcmp(const char*str1,const char*str2)//字符串只是进行比较,并会改变值,因此可以用const修饰
{
  assert(str1 && str2);
  while (*str1 == *str2)
  {
    if (*str1 && *str2 == '\0')//字符串相等
    {
      return 0;
    }
    str1++;
    str2++;
  }
  return (*str1 - *str2);
}
int main()
{
  char arr1[] = "abcsdf";
  char arr2[] = "nihao";
  int ret=my_strcmp(arr1, arr2);
  printf("%d", ret);
  return 0;
}
-13

上述所讲的strcpy/strcat/strcmp函数,都是不受长度限制的函数,因此特们不太安全,有时会强制性的进行字符串操作。因此我们引出下受长度限制的字符串函数:

长度受限制的字符串函数:strncpy/strncat/strncmp

strncpy:charstrncpy(chardest,onst char*res,size_t count(单位是字节))

拷贝num个字符从源字符串到目标空间,如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加\0,直到num个

举例:

int main()
{
  char arr1[30] = "abcdef";
  char arr2[] = "bit";
  strncpy_s(arr1, arr2, 8);
  printf("%s ", arr1);
  return 0;
}
bit
strncat:charstrncat(chardest,const *strres,size_t count)

指定长度的追加,追加完毕后,给后面加\0

举例:

#include<stdio.h>
#include<string.h>
int main()
{
  char arr1[30] = "hello";
  char arr2[] = "world";
  strncat_s(arr1, arr2, 3);
  printf("%s\n", arr1);
  return 0;
}
hellowor
strncmp:int strcmp(const charstr1,const charstr2,size_t num)

标准规定: 第一个字符串大于第二个字符串,则返回大于零的数字

第一个字符串小于第二个字符串,则返回小于零的数字

两个字符串相等,返回0

举例:

int main()
{
    char arr1[30] = "abblo";
    char arr2[] = "abbld";
    int ret = strncmp(arr1, arr2, 4);//第三个参数为比较的字节数
    printf("%d ", ret);
    return 0;
}

strncmp函数和strcmp函数不同的是,该函数对所比较的字符长度进行了限制,如上述所示arr1(abblo)和str2(abbld),前四个元素的ASCII码是相同的,但由于我们对二者所比较的长度进行了限制,因此,第五个元素并不会进行比较,所以输出结果为0

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