深入C语言字符串

注意*

字符串在内存中是连续的

HEL       LO\0
721011081081110

知识扩展*:C语言规定,字符串以0结尾,\0就等于数字0

知识扩展*:字符串格式是规定以“\0”结尾,在打印的时候“\0”并不会显示,统计长度的时候也是统计有效长度。这单纯地只是一个标志位,并不是元素,如果没有这个标志,那么如果有两段字符串在内存中连续存储,就无法判断是两端字符串还是一段字符串,\0是字符串结束符,不是可见字符,不可见字符很多,比如空格就是个典型的不可见字符,它只能通过前后字符的位置间接看见,不可见字符不可被打印。

用数组和指针声明字符串

char array[0xFF] {"Hello"};
char* str1  {(char*) "Hello"];
std::cout<<array;
std::cout<<&array;
std::cout<<&array[0];

字符串是一个常量类型,也就是const char*,所以要用显示类型转换

以上,如果打印array,就会打印出它的值,如果想要打印它的地址,就要在前面取址,这是因为cout 会将 字符数组的首地址指向的数据输出,同理,第三次打印也是打印出H,而不是地址,如果想打印它的地址值,要这么写

     char str[]{ "123456" };
     char * ch = &str[0];
     std::cout << &ch;
    char array[5]{};
    array[3] = '*'; array[4] = '*';
    std::cout << &array[3];

知识扩展*:cout输出的是个 char*类型,当做字符串处理,将会一直输出,直到遇到'\0'为止,所以这里打印了两个*,而不是一个*

同样,在下面的例子中,如果打印str,也会打印出它所指的内存空间的值,如果要打印它所指的内存空间,就要用道%p

    char* str{ "123456" };
    std::cout << str<<std::endl;
    printf("%^p",str);

第一行打印出了123456,第二行打印出了地址

知识扩展*:在上面两个例子中,双引号做了3件事:  1.申请了空间(在常量区),存放了字符串 2. 在字符串尾加上了'/0'     3.返回地址,然后让array和str接收了这个地址

如果当前计算机是中文编码GBK,则字符在内存中显示为

       三\0
d5c5c8fd00

因为每个汉字是两个字节,而英文还是一个字节

如果用宽字节来声明字符串,则每个字符在内存中显示为两个字节,不论中英文

He           0
48006500205f0000

假设编译器采用utf-16,则‘张’在内存中顺序为205f,而打印它的内存地址后,显示为0x5f20,这是因为字符串的顺序是从左到右,数据储存的时候是低位在前高位在后,是从右到左。

此时输出张,控制台不一定能输出,因为编译器虽然认识张,但是控制台可能采用的ANSI编码,此时就要调用头文件locale,并且通过setlocale函数设置中文每个字符占用两字节

知识扩展*:以十六进制输出字符串每个字符

wchar_t wcharA[0xff] {"Hello"};
for(int x=0;x<10;x++)
{
    std::cout<<std::hex<<wcharA[x]<<std::endl;
}

scanf输入字符串

这里假设输入的Name是tony,所以Name需要5个字节,四个字节是tony,最后一个字节放0,如果是’张三‘,则需要5个字节,因为中文占两个字节

char Name[0x5];
scanf("%s",Name);
printf("%s",Name);

wchar_t wcharA[0xFF];
wscanf ("%s",  wcharA);
wprintf ("%s", wcharA);

wchar_t输入输出前要加w,如果要输出中文,还要设置对应的头文件

安全问题

因为字符串也是数组,如果输入的字符串长度超过了数组长度,可能就会造成数据越界访问攻击,输入的字符串多出的部分,可以达到修改数据 的目的。

scanf_s

scanf_s("%s",str,可接受的最大字符值)

特别注意*:std::cout会把char类型的指针当成字符串来处理,不显示地址,显示它的值

strlen

语法  strlen(str)

返回char类型的字符串长度,不能计算中文

wcslen

语法  wcslen(str)

返回宽字节字符串长度,可以计算中英文

思考

如何计算char类型的字符串长度,以及如何计算char类型的中英文混合

    char strA[6]{ "HELLo" };
    int count = 0;
    while ('\0' != strA[count])
    {
        count++;
    }
    std::cout<<count;

注意*:这里是字符\0,而不是字符0,字符\0的ASCII为0,而字符0的ASCII是48

    char strA[10]{ "HELLo你好" };
	int count = 0;
	for (int i = 0; strA[i]; i++)
	{
		if (strA[i] < 0) i++;
		count++;
	}
	std::cout << count;

这里。strA[i],i最大的时候的值为0,所以可以在循环中直接这么写。GBK规定,只要第一个字符大于127,就是中文字符,所以只要字符取值超过127就表示中文,而每个字符取值范围是-128~127,超过127就是负数了

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值