c++ string 与 c 风格 数组得输入笔记

c语言

写在前面 闲谈

我好像很久没有写过博客了,也不是完全没有写,写过几篇都保存在本地或者发布到了其他平台上,都想不起来是写什么了。没有归纳汇总起来。最近香重构一下编译原理实验的词法分析程序,由于cpp里面得cin cout 比起C语言里面的printf 方便太多,所以,每次写c的时候,我都习惯性的创建cpp项目,但是,代码却用的很多c风格代码,一方面对cpp并不熟悉,另一方面,我觉得cpp封装了很多的方法对代码确实简化了很多操作,但是我不认为我自己能用c很好的实现这些方法,为了锻炼自己的代码能力,我更想自己使用c实现这些方法。

另一个,出血编程的人总是掉入一个思想陷阱,据我了解,并不是我一个人又这种想法,这只是一种错误认识罢了:总担心自己多写了一个变量,多调用一个函数十七叠加一层栈会大大降低程序运行效率,在目前这种小程序编程上,这种想法简直是累赘,并且有些过分,实际上从很多开源项目代码看来,适量的函数调用和变量使用是有利的,千万不要为了一点点的效率提升而牺牲了很大的程序可读性,很多软件代码都是好几千万行,人家运行的好好的。

另一方面,我自己对cpp的理解,c和cpp本是一家,在以前cpp甚至没有自己的编译器,是靠翻译成c语言进行编译,一度让人认为cpp并不是一门独立的编译语言。其次,cpp里面能够直接写c代码,用c的头文件,让我对于cpp和C语言始终混写。不过,后来我看到了

1
2
3
extern c{
//.....
}

这中写法是为了提醒编译器使用c语法调用函数。而我cpp 和 c混写立马显得十分不雅。于是我准备看一下cpp并尽量使用cpp风格代码。好了,下面是第一个探索成果,其实我并不想写,一方面,这个点内容太少,而且是基础操作。不过,发烧了,脑子记忆力很差,我可不想日后翻着数去重新找重点。另外,事无大小,悉数记录,写博客是一个好习惯,过来太长事件,是该活跃一下了。

c风格字符串输入

在c语言里面,字符串使用字符数组定义的

1
char str[];

提供了几个诸如 get scanf的输入方式,不过他们并不安全,因为他们并不检查是否越界,虽然提供了更加安全的函数,但是这页使得编写过程更加复杂。

这种类型的字符串结尾需要用0标记结束,否则,printf,cout 这样的函数就会一直读取直到遇到下一个为0的地方,这可能引起程序错误。str定义以后,就不能更改其大小,所以,在很多我们不知道输入字符串大小的时候,不得不考虑他的最大值,或者做长度限制以确保安全正确的输入。除此之外,你并不能将一个数组的值直接给另一个数组。而这些在cpp提供的string数组里面变得很容易。

cpp String

cpp里面提供了一个string类存储字符串,这让我们可以把字符串作为一个对象来操作。要使用string对象,我们只需要包含头文件string 提供了很多类c的体验,例如下标取值等操作,但是这些不重要,重要的是他和c不一样的地方。

字符串拼接

  • string允许我们方便的将两个字符串合并,只需要香普通运算一样 str1 + str2 这样的写法,拼接不会再两个字符串之间添加空格,并且,不用担心合并后的字符串的越界问题,string会始终自动调整大小以容纳字符串。

  • 而c语言的数组类型(以下简称数组)可以使用strcat(),strcat接受两个参数,str1,str2,会将str2的值追加到str1后面,不过strcat并不会计算str1的长度,所以你需要确保合并后的长度小于str1的容量。

字符串长度

  • string 可以使用str.size() 得到字符串的长度

  • 数组 可以使用C语言的strlen函数获得字符串长度,不过注意,strlen将0 作为结束标记,所以,如果你结尾忘记加0,那他会一直计算个数直到为0。还需要注意的地方,sizeof操作符可以获取数组的大小,注意是整个数组所占空间的大小,这与strlen并不相同。

    为了更好的说明这个问题,我们可以写以下代码

    1
    2
    3
    char a[] = "abcde";
    printf("%d",sizeof(a));
    printf("%d",strlen(a));

    运行结果是6 5,因为a的长度就是6,包含最后一个0字符,

    再看以下代码

    1
    2
    3
    4
    char a[10];
    strcpy(a,"abcde");
    printf("%d",a);
    printf("%d",strlen(a));

    运行结果是10 5,因为定义的a大小是10,

字符串输入

对于string 和 数组,再cpp里面,我们都可以使用cin进行输入,但是他们是不一样的,现在,我们只要直到可以在喝么用,并不用深究原理,我要说的是get 和 getline()读取输入。

使用cin

1
2
3
char str[10];
cout << "pls input your name:"
cin >> str;

我们可以使用这样的方式接收输入,但是cin以空格和回车作为结束标志,所以,对于以上代码,如果你这么输入

1
aja su

那么后面的su将被保存到缓冲区中等待下一次输入。所以,一般情况下,如果你的输入包含空格,你需要直接读取一行数据

读取一行数据

对于数组,可以使用cin.get(str,size) 或 cin.getline(str,size) 读取下一行的数据,接受两个参数,返回一个cin对象。第一个参数是将读取的输入保存到哪里,第二个参数是最多读取几个字符,避免溢出。get 与 getline的区别在于getline会读取并抛弃该行最后的换行符,而get不会。所以如果一次需要读取多行数据时,当用get(str,size)读取时,那么下一次将读取到一个空串,以为,下一个字符是换行符,所以,会被当作是结束的标志。所以,如果你只使用cin.get(str,size) 这种方式,你将永远都读不到下一行数据。不过,如果使用不带任何参数的cin.get(),将会读取丢弃换行符。

所以你同样可以这样读取多行数据

1
2
3
cin.get(str1,size);
cin.get();
cin.get(str2,size);

对于string,可以使用get(cin,str) 和 getline(cin,str), 注意,并不需要带cin. 因为他并不是cin的成员函数。输入参数第一个参数表明去哪里获取输入,而第二个参数表明将读取的数据存到哪里。这个地方的解释是:istream设计的时候cpp还没有string类,所以没有包含该对象的方法实现。

其他类型字符串

wchar_t str[] = L”abcd”;

char16_t str = u”abcde”;

char32_t str = U”abcde”

或者是utf8 编码支持 添加u8前缀

原始字符串

1
cout << R"("this is a raw string \n ")" <<endl;

将会输出”this is a raw string \n “

如果你想输出 ()

那么你可以在 “( 之间提娜姬其他字符以标记开头和结尾

例如

1
cout << R"+++//("(this is a raw string \n )")+++//" <<endl;

就可输出(this is a raw string \n )”

2021-04-25 12:20AM

Author: 哒琳

Permalink: http://blog.jieis.cn/2021/22a99117-0611-4a0a-a3e1-1d745475ae17.html

Comments