字符串和字符串函数

本文详细介绍了C语言中字符串的概念,包括字符串的定义、常量、指针与数组的区别,以及字符串的赋值、输入(gets(),fgets(),scanf())、输出(puts(),fputs(),printf())和常用字符串函数如strlen(),strcmp(),strcpy(),strcat()的使用。同时,讨论了字符串输入时的注意事项和安全版本的函数如strncpy(),strncat(),strncmp()等。
摘要由CSDN通过智能技术生成

字符串

关于字符串

字符串的定义

以0结尾的一串字符

  • 0或’\0’是一样的,但是’0’不同

0标志字符串的结束,但它不是字符串都一部分

  • 计算字符串长度时候不包含这个0

字符串以数组的形式存在,可以以数组或指针的形式访问

字符串常量

char* s = "Hello, world!";

  • s是一个指针,初始化为指向一个字符串常量
    • 由于这个常量所在的地方,所以实际上s是const char* s
    • 不能对s所指的字符串做修改
  • 如果需要修改字符串,应该用数组
    • char s[] = "Hello, world!";
指针还是数组?

char *s = "Hello, world!";
char s[] = "Hello, world!";
数组:这个字符串在这

  • 作为本地变量空间自动被回收

指针:不知道这个字符串在哪里

  • 处理参数
  • 动态分配空间

字符串赋值

char *t = "Hello, world!";
char \*s;
s = t;
并没有产生新的字符串,只是把t的地址给了s

空字符串

char buffer[10] = "";

  • 这是一个空的字符串,buffer[0]是’\0’

char buffer[ ] = "";

  • 这个数组的长度只有1

字符串数组

char **a

  • a是一个指针,指向一个指针,那个指针指向一个字符串

char a[][]

程序参数

  • int main(int argc, char const*argv[])
  • argv[0]是命令本身

字符串输入

如果想把一个字符串读取到程序中,必须首先预留存储字符串的空间,然后使用输入函数来获取这个字符串,C库提供了三个读取字符串的函数:scanf()gets()fgets()

创建存储空间

可以通过数组(char name[10])来分配存储空间,也可以通过C语言动态内存分配函数来动态分配存储空间

char *name;
scanf("%s", name);

如果通过上面的代码来创建存储空间,可能会通过编译器,但是在读入name的时候,name会覆盖程序中的数据和代码,并可能导致程序异常终止。这个是 因为scanf()把信息复制到由name指定的地址中,而在这种情况下,参数是个 未被初始化的指针,name可能指向任何地方

gets()函数

因为字符串没有预定的长度,所以gets()函数通过判断遇到的第一个换行符\n结束输入,按回车键可以产生这个字符。它读取换行符之前(不包括换行符)的所有字符,并在这些字符后添加一个空字符\0

下面是一段报错代码

[clef@rhel6164 c]$ cat test1.c
#include <stdio.h>
#define MAX 81

int main(void){
    char name[MAX];
    char *ptr;//定义一个char类型的指针

    printf("Please input your name.\n");
    ptr = gets(name);//使用一个地址把字符串
    //gets()函数使用return返回字符串的地址
    printf("name, %s\n", name);
    printf("ptr, %s\n", ptr);

    return 0;
}

如果在gets()函数在读取字符串时 出错或者遇到文件结尾,它就返回一个空(或0)地址,这个空地址被称为 空指针,并且stdio.h里面定义的常量 NULL来表示,可以用下面的代码来进行一些错误检测

while(get(name) != NULL)

也可以通过getchar函数来完成上面的错误检测

while((ch = getchar()) != EOF)

注意:空指针和空字符是不一样的,不要混淆。空指针是一个地址,而空字符是一个char类型的数据对象其值为0,数字上都可以用0表示,但是概念不同:NULL是一个指针,而0是一个char类型的常量

fgets()函数

因为gets()函数不会检查存储区是否能够容纳实际输入的数据,多出来的字符简单地溢出到相邻的内存区,所以上面的代码在编译的时候会有warning。fgets()函数和gets()函数的不同:

  • 它需要第二个参数来说明最大读入字符数。如果这个参数值为n,fgets()就会读取最多n-1个字符或者读完一个换行符为止(因为会自动添加一个空字符(\n)),由这两者中最先满足的那个结束输入
  • 如果fgets()读取到换行符,就会把它存到字符串里,而不是像gets()那样丢弃
  • 它还需要第三个参数来说明读哪一个文件,从键盘上读取数据时,可以使用stdin(代表standard input)作为参数,这个标识符在stdio.h中定义
#include<stdio.h>
#define MAX 81

int main(void)
{
    char name[MAX];
    char *ptr;

    printf("Please input your name.\n");
    ptr = fgets(name, MAX, stdin);
    printf("name, %s\n", name);
    printf("ptr, %s\n", ptr);

    return 0;
}

编译运行结果

[clef@rhel6164 c]$ gcc test1.c //这里就没有warning出现
[clef@rhel6164 c]$ ./a.out
Please input your name.
clef
name, clef
//注意这里的换行符,因为fgets()函数没有丢弃输入的换行符
ptr, clef

[clef@rhel6164 c]$

scanf()函数

scanf()函数可以使用%s格式来读入一个字符串,scanf()函数和gets()函数的主要区别在于如何决定字符串何时结束。scanf()函数更基于获得单词(get word)而不是获取字符串(get string)。scanf()函数有两种方法决定输入结束,无论哪一种都是遇到的第一个非空白字符开始

  • 如果使用%s格式,字符串读取到(但不包括)下一个空白字符(比如空格、制表符或换行符)
  • 如果指定了字段宽度,比如%10s,scanf()函数就会读取10个字符或者直到遇到第一个空白字符,由二者最先满足的那一个终止输入

字符串输出

puts()函数

puts()函数使用很简单,只需要给出字符串参数的地址,它遇到空字符(\0)就会结束输出(所以必须要有空字符)。puts()函数在显示字符串的时候,会自动在其后添加一个换行符(\n)
puts()函数的作用与语句“printf(“%s\n”,s);的作用相同。注意:puts在输出字 符串后会自动输出一个回车符

[clef@rhel6164 c]$ cat test1.c
#include<stdio.h>
#define DEF "I am a #defined string."

int main(void)
{
    char str1[80] = "An array was initialized to me.";
    const char * str2 = "A pointer was initialized to me.";

    puts("I am an argument to puts()."); //直接用字符串做参数
    puts(DEF); //用宏定义做参数
    puts(str1);
    puts(str2);
    puts(&(str1[5])); //必须用括号strl1[5],因为str1将会首先结合&,然后在[5]结合,将出错
    puts(str2+4);

    return 0;
}

编译&执行:

[clef@rhel6164 c]$ gcc ./test1.c
[clef@rhel6164 c]$ ./a.out
I am an argument to puts().
I am a #defined string.
An array was initialized to me.
A pointer was initialized to me.
ray was initialized to me.
inter was initialized to me.

fputs()函数

fputs()函数面向文件版本,两者主要的区别是:

  • fputs()函数需要第二个参数来说明要写的文件,可以使用stdout(standard output)作为参数来进行输出显示
  • 与puts()函数不同,fputs()函数并不为输出自动添加换行符

读取一行并把它回显在下一行,用下面的两种循环都可以办到

char line[81];
while(gets(line)) //遇到文件结尾,gets()函数就会返回空指针,循环结束
{
    puts(line);
}
char line[81];
while(fgets(line,81,stdin)){
    fputs(line,stdout);
}

printf()函数

如同puts()函数一样,printf()函数在输出字符串的时候同样需要一个字符串地址作为参数,但是printf()函数没有puts()函数方便,但是它可以格式化多种数据类型,输出的时候也不自动添加换行符

字符串函数

单字符的输入输出

putchar

int putchar(int c);
向标准输出写一个字符
返回写了几个字符,EOF(-1)表示出错

getchar

int getchar(void);
从标准输入读一个字符
返回类型是int,因为要处理EOF

string.h

strlen

size_t strlen(const char *s);
返回s的字符串长度,不包括’\0’

  • 以’\0’作为结束标志
strcmp

int strcmp(const char *s1, const char *s2);
比较两个字符串,返回值:

  • 0 :相等
  • -1:s1 < s2
  • 1 :s1 > s2

注意

  • 两个字符串从左到右按照 ACSII 码值大小比较,直到出现不同的字符或者遇到’\0’为止
  • 若出现不相同的字符,则以第一对不相同的字符的比较结果为准
  • 字符串1等于字符串2,函数值为0,字符串1大于字符串2,函数值为正整数,字符串1小于字符串2,函数值为负整数
stricmp

int stricmp(const char *s1, const char *s2);
忽略大小写比较两个字符串,返回值同strcmp

strcpy

char *strcpy(char *restrict dst, const char *restrict src);
把scr的字符串拷贝到dst

restrict:告诉编译器,dst和src指向的内存不能重叠

返回dst,为了能链起代码来
注意

  • 若开始没有对字符数组1进行初始化或者赋值,str1中的内容是无法预知的,复制时str2将内容和结束符一起复制到str1中,而此时str1字符数组结束符后面的剩余空间的字节内容不一定是’\0’
  • 不能用赋值语句将字符串常量或者字符数组直接赋值给字符数组,如str1=“world”;这写法是错误的,必须要用strcpy()函数,用赋值语句将一个字符赋值给字符型变量或者字符数组是可以的
复制一个字符串
char *dst = (char*)malloc(strlen(src)+1);
strcpy(dst, src);
strcat

char *strcat(char *restrict s1, const char *restrict s2);
把s2拷贝到s1后面,接成一个长的字符串,返回s1(s1必须有足够空间)
注意

  • 字符串2连接到字符串1的后面,将连接后的结果放在字符数组1中,最后得到字符数组1的地址
  • 两个字符串后面均有结束符’\0’,在连接时字符串1后面的结束符会被取消,只在新串最后保留结束符
安全版本

char *strncpy(char *restrict dst,const char *restrict src, size_t n);

char *strncat(char *restrict s1, const char *restrict s2, size_t n);

n表示最多拷贝多少个字符

int strncmp(const char *s1, const char *s2, size_t n);
比较两个字符串的前n个字符,返回值同strcmp

strchr

char *strchr(const char *s, int c);
返回s中第一个c的位置,找不到就返回NULL
char *strrchr(const char *s, int c);
返回s中最后一个c的位置,找不到就返回NULL

strstr

char *strstr(const char *s1, const char *s2);
在字符串中查找s2,返回s1中第一次出现s2的位置,找不到就返回NULL
char *strcasestr(const char *s1, const char *s2);
忽略大小写,和strstr一样

strlwr和strupr

大写转小写:strlwr(字符数组)
小写转大写:strupr(字符数组)

int main(void)
{
    char str[15] = "Hello";
    _strlwr_s(str,sizeof(str));//第一个参数传一个char类型的指针,可以传一个数组,第二个参数传入strlen(str) + 1
    puts(str);
    
    _strupr_s(str, sizeof(str));//调用时的第二个参数,确保其足够容纳整个字符串加上结束符,这样就能正确处理整个字符串并避免潜在的问题
    printf("%s\n",str);
    
    return 0;
}

结果

hello
HELLO
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值