c语言中的字符串

字符串

定义字符串的几种方式:

  1. char c[] = {'h','e','l','l','o'};
    

    这种是字符数组

    可以用for循环打印:

    for(int i=0;i<5;i++)
        printf("%c",c[i]);
    

    不推荐用下面两种方式打印,因为输出结果最后会多出个小方框的符号(gcc编译器):

    printf("%s\n",c);
    puts(c);
    

    输出结果:
    在这里插入图片描述

  2. char c[] = "hello";
    

    可用下面三种方式打印:

    for(int i=0;i<5;i++)
        printf("%c",c[i]);
    printf("%s\n",c);
    puts(c);
    
  3. char *c = "hello";
    

    可用下面三种方式打印:

    for(int i=0;i<5;i++)
        printf("%c",*(c[i]);
    printf("%s\n",c);
    puts(c);
    

字符串的一些性质

  1. char c[] = "hello";
    

    这样定义的是字符串变量,它(数组元素)允许修改

    c[0] = 'H';
    puts(c);
    

    输出结果:

    Hello
    
  2. 用数组形式定义字符串,数组名就是地址常量,不能更改。如果改变了数组名,则意味着改变了数组的存储位置。可以进行类似数组名+1这种操作,标识数组的下一个元素。但是不能进行++数组名这样的操作。递增运算只能用于变量名前,不能用于常量:

    char arr[] = "Hello World!";
    int i = 0;
    printf("%c  ",*(arr+1));
    //printf("%c  ",*(arr++));//error
    
  3. char *p = "hello";
    

    这样定义是字符串常量,它不允许被修改:

    *p = 'H';//error
    

    这样写不会报错,但是会导致程序崩掉

  4. 用指针形式定义的字符串,可以使用类似++指针名这样的操作

    char *s = "Hello World!";
    printf("%c\n",*(++s));
    

    输出结果是:e

动态内存分配和字符串

char *p;
*p = 'H';
printf("%c\n",*p);

运行上面的代码尽管不会报错,但是程序运行到第二句会崩掉,第三局不会执行。原因是因为p是野指针(不知道指向哪里),对野指针进行赋值相当于直接修改内存里面某个地方的值,而这个值用户并没有权限修改。

char *p = (char *)malloc(1);
*p = 'H';
printf("%c\n",*p);

修改成上面代码,malloc()函数在内存分配了一个空间,这个空间对用户来说是可以操作的。把这个空间的地址赋给指针p,这样就能通过指针p来修改这个空间里面的值

sizeof()

  1. sizeof与字符数组:

    char c[] = {'h','e','l','l','o'};
    printf("%d\n",sizeof(c));
    printf("%d\n",sizeof(c[0]));
    printf("%d\n",sizeof(c)/sizeof(c[0]));
    

    输出结果:

    5
    1(一个字符占一个字节)
    5
    
  2. sizeof与字符串:

    char c[] = "hello";
    printf("%d\n",sizeof(c));
    printf("%d\n",sizeof(c[1]));
    printf("%d\n",sizeof(c)/sizeof(c[0]));
    

    输出结果:

    6
    1
    6
    

    系统会自动在字符串"hello"最后加多一个字符串的结束标志:\0,因此结果为6,字符数组则不会加

strlen()

strlen()得到的是有效字符数,而且它不会算上系统为字符串添加的结束符

  1. char c[] = "hello";
    printf("%d\n",sizeof(c));//输出结果:6
    printf("%d\n",strlen(c));//输出结果:5
    
  2. char c[100] = "hello";
    printf("%d\n",sizeof(c));//输出结果:100
    printf("%d\n",strlen(c));//输出结果:5
    
  3. char *c = "hello";
    printf("%d\n",sizeof(c));//输出结果:8
    printf("%d\n",strlen(c));//输出结果:5
    

    sizeof(c)在这里得到的是计算机用多少字节来表示一个地址(等同于sizeof(char *)

strcpy()

用于拷贝字符串,这个函数在头文件string.h里被定义

原型是char *strcpy(char* dest, const char *src),两个参数分别是“拷贝到哪里去”和“从哪里拷贝”

小例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
    char *p = (char *)malloc(15);
	strcpy(p,"HelloWorld");
	puts(p);
    return 0;
}

上面分配空间的语句如果只申请1个字节:(char *)malloc(1),编译器尽管不会报错,结果也能正常输出,但不可以这么做。能正常输出只是刚好后面的内存没有其它程序在用,如果后面的内存被占用了则上面的这个程序就会崩溃

补充

  • 如果p1和p2都是指向字符串的指针,则p1 = p2;这个语句只是拷贝字符串的地址,而不是字符串本身

  • 注意下面这种字符串赋值是不正确的:

    char c[20];
    target = "Hello World!";
    

    正确的应该是:strcpy(c,"Hello World!");

  • 不能对未初始化的指针进行赋值:

    char * c;
    strcpy(c,"Hello World");
    

    c未被初始化,该字符串可能被拷贝到任何地方。

  • strcpy()接受两个字符串指针作为参数

  • strcpy()返回的类型是char *,返回的是第一个参数的值(见小例子二)

  • strcpy()第一个参数不必指向数组(或指针)的开始,它可以只拷贝数组的一部分(见小例子二)

小例子二:

char *c1 = "beast";
char c2[40] = "Be the best that you can be.";
//char *c2 = "Be the best that you can be.";//error,不会报错,但是程序运行不起来,原因:beast是字符串常量,不能修改
char * c3;	
c3 = strcpy(c2 + 7,c1);
puts(c2);
puts(c3);	

输出结果:

Be the beast
beast

由于strcpy()第一个参数是c2+7,所以c3指向c2中的第8个元素,因此输出为beast

strncpy()

strcpy()不能检查目标空间是否能容纳字符串的副本,使用strncpy()拷贝更安全

strncpy(target,source,n)三个参数:

  1. target:拷贝去哪里
  2. source:要拷贝的东西
  3. n:拷贝多长(多少字节)

strncpy(target,source,n)把source中的n个字符或空字符之前的字符拷贝至target中

  • 如果source中的字符数小于n,则拷贝整个字符串,包括空字符

    char * p = "abc";
    char c[] = "ABCDE";
    strncpy(c,p,4);
    printf("%s\n",c);
    

    输出结果:abc

  • 如果source中的字符数大于n,则一直拷贝到n,不带空字符

    char * p = "abc";
    char c[] = "ABCDE";
    strncpy(c,p,2);
    printf("%s\n",c);
    

    输出结果:abCDE

因此拷贝后,target中不一定会有空字符

scanf()

能用于获取用户输入的字符串

char c[128] = "\0";
scanf("%s",c);
puts(c);

这里要注意一点,如果输入像“Hello World”这种带有空格的字符串,scanf()只会读入“Hello”,而忽略掉“World”,所以最终只会输出Hello

%s:从第1个非空白字符开始,到下一个空白字符之前的所有字符都是输入

gets()

能用于获取用户输入的字符串

gets()读取整行的输入,直至遇到换行符,然后丢弃换行符,存储其余字符,并在这些字符的末尾添加一个空字符使其成为一个C字符串。 ——《C Primer Plus》

char c[128] = "\0";
gets(c);
puts(c);

注意:gets()无法检查数组是否装得下所输入的字符串。因此如果要使用gets()的时候一定要保证有足够的空间

如果输入的字符串过长,会导致缓冲区溢出,即多余的字符超出了指定的目标空间。如果这些多余的字符只是占用了尚未使用的内存,就不会立即出现问题;但如果它们擦写掉程序中的其他数据,会导致程序异常终止。 ——《C Primer Plus》

strcat()

用于拼接两段字符串。原型是:char *strcat(char *dest, const char *src),把src所指向的字符串(包括\0)复制到dest所指向的字符串后面(删除*dest原来末尾的\0)。

要自行保证*dest有足够空间容纳拼接后的字符串

*src中原有的字符不变

strcat()返回指向dest的指针

char *p = "abc";
char c[128] = "ABC";
strcat(c,p);
puts(c);//ABCabc

strcmp()

用于比较两个字符串

原型是int strcmp(const char *str1, const char *str2)

  • str1str2相同,则返回零
  • str1<str2,则返回负数
  • str1>str2,则返回正数

多数情况下只需关心strcmp()的返回值是否为0即可

assert()

用于某个检测表达式是否为真,如果为假则终止程序

使用assert()需包含头文件assert.h

频繁调用assert()会极大影响程序的性能

assert(表达式);
类似于:
if(表达式)
{
    ...;
}
else
{
    报错&&终止程序;
}

strcmp()

用于比较两个字符串

原型是int strcmp(const char *str1, const char *str2)

  • str1str2相同,则返回零
  • str1<str2,则返回负数
  • str1>str2,则返回正数

多数情况下只需关心strcmp()的返回值是否为0即可

assert()

用于某个检测表达式是否为真,如果为假则终止程序

使用assert()需包含头文件assert.h

频繁调用assert()会极大影响程序的性能

assert(表达式);
类似于:
if(表达式)
{
    ...;
}
else
{
    报错&&终止程序;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值