C语言字符概念,C语言风格字符串的概念、定义、输入字符串、输出字符串

字符串: C语言中最有用、最重要的数据类型之一。

字符串:是以\0字符结尾的char类型数组。所以可以把数组和指针知识应用于字符串。

如何在程序定义字符串:

1、字符串字面量

用双引号括起来的内容称为字符串字面量,也叫作字符串常量。双引号中的字符和编译器自动加入末尾的\0字符,都作为字符串储存在内存中。

如果要在字符串内部使用引号,必须要在双引号前面加上一个反斜杠(\)。

字符串字面量被视为const,就不能更改了。

字符串常量属于静态存储类别。这说明如果在函数中使用字符串常量,该字符串只会被储存一次,在整个程序的生命期内存在,即使函数被调用多次。用双引号括起来的内容被视为指向该字符串储存位置的指针。

2、字符串数组和初始化

定义字符串数组时,必须让编译器知道需要多少空间,一种方法是足够空间的数组储存字符串。

指定数组大小的时候,必须确保数组的元素个数至少比字符串长度多1;

省略数组初始化声明中的大小,编译器会自动计算数组的大小;

数组表示法_创建字符串:char words[MAXLENGTH]=“I am a string in an array.”

指针表示法_创建字符串:char * pt1 = “Something is pointing at me.”

3、数组和指针

数组表示法_创建字符串:char words[MAXLENGTH]=“I am a string in an array.”

这种表示法,字符串字面量被存储在静态存储区。数组只有在运行时才会被分配内存。此时,才将字符串拷贝到数组中。此时字符串有两个副本,一个是在静态内存中的字符串字母量,另一个是储存在words数组中的字符串。

指针表示法_创建字符串:char * pt1 = “Something is pointing at me.”

编译器为字符串在静态存储区预留了29个元素的空间。一旦开始运行程序,它就会为指针变量pt1留出一个储存位置,并把字符串的地址储存在指针变量中。

4、数组和指针的区别

char heart[] = “I love Tillie!”;  ->数组名heart是常量;

const char *head = “I love Millie!”; ->指针名是head变量;

head =heart ->可以;

heart =head –>不可以,非法构造,赋值运算符左边必须是变量;

5、字符串数组

const char *mytalents[LIM]={

"Adding number swiftly",

"Multiplying accurately",

"Stashing data",

"Following instructions to the letter",

"Understanding the C language"

};

char yourtalents[LIM][SLEN]={

"Walking in a straight line",

"Sleeping","Watching television",

"Mailing letters","Reading email"

};

字符串数组分配内存的使用率低。因为数组中储存着字符串字面量的副本。每个字符串都被储存了两次。

如果要使用数组表示待显示的字符串,建议使用指针数组。指针数组也有缺陷,就是字符串字面量不能更改。如果要改变或者为字符串输入预留空间,不要使用指向字符串字面量的指针。

++++++++++++++++++++++++++++++++++++++++++++++++++++++

字符串的输入:

想把字符串读入程序,首先必须预留储存该字符串的空间。然后用输入函数获取该字符串。

如何分配空间:

要做的第1件事就是分配空间。以储存稍后读入的字符串。意味着必须为字符串分配足够的空间。不能指望计算机在读取字符串时顺便计算它的长度。

char *name;

scanf(“%s”,name);

name是未初始化的指针,name可能指向任何地方。所以可能会擦写掉程序中的数据或代码,从而导致程序异常中止。

最简单的办法:在声明时显式指明数组的大小。

char name[81];

现在name是一个已分配块(81字节)的地址。还有一种办法就是使用C库函数来分配内存。

空字符:

用于标记C字符串末尾的字符;对应的字符ASCII编码是0;

空指针:

有一个值,该值不会与任何有效的地址对应。

本质上讲空字符是整数类型,占1个字节;

空指针是指针类型,是一个地址,占4个字节。

丢弃输入行中余下的字符,是因为,输入行中多出来的字符会被留在缓冲区中。成为下一次读取语句的输入。

1、gets() 函数    这个函数不安全,被摒弃了

scanf()和转换说明%s只能读取一个单词,可是在程序中经常要读取一整行输入,而不仅仅是一个单词。

很久前gets()就用于处理这种情况。gets()函数简单易用,它读取整行输入,直至遇到换行符。

gets()函数有个问题,无法检查数组是否装得下行。数组名会被转换成数组首元素的地址。get()函数只知道数组的开始处,并不知道数组中有多少个元素。

如果输入字符串过长,会导致缓冲区溢出(buffer overflow)。多余的字符超出了指定的目标空间。如果这些多余的字符只是占用了尚未使用的内存,就不会立即出现问题。但是一旦擦写掉程序中的其他数据,就会导致程序异常中止。

C99标准建议不要使用get()函数,甚至被C11标准摒弃了。

2、fgets()函数

函数原型:char *fgets(char *buf, int bufsize, FILE *stream);  ---->从指定的文件读取一个字符串

buf 字符型指针,指向存储读入数据的缓冲区的地址;---->存到哪

n 从流中读入n-1个字符;--->读多少个

stream 指向读取的流;   --->从哪读

会在读入的最后一个字符后加上串结束标志'\0'

返回值:读取失败或读到文件结尾返回NULL;输入成功时,返回 char 型指针,指向读入的字符串内容,含换行键;

为什么会有换行符问题:因为输入时会敲回车嘛,就产生换行符。函数会把换行符一并存储起来。(读一行字符串的范畴)

fgets()会存储换行符,有好处也有坏处。好处就是:检查末尾有没有换行符就知道是否读取了一整行。坏处就是:你可能并不想把换行符储存在字符串中,这样的换行符会带来一些麻烦。

如何处理掉换行符:在已经储存的字符串中查找换行符,将其替换成空字符

while (words[i] != ‘\n’)

i++;

words[i]=’\0’;

3、gets_s()函数

函数原型: gets_s(words,STLEN);

只从标准输入中读取数据,不需要第3个参数;

如果读到换行符,会丢弃它,而不是储存它;(不存换行符)

如果读到最大STLEN字符数的话,.....很复杂;

没有fgets()函数灵活,易用;不建议用;

4、s_gets()函数

函数实现如下:

char * s_gets(char * st, int n)

{

char * ret_val;

int i=;

ret_val = fgets(st, n, stdin); //读取成功,返回一个指针,指向输入字符串的首字符;

if(ret_val)

{

while(st[i]!='\n' && st[i]!='\0')

i++;

if(st[i] =='\n') //fgets会把换行符也吃进来了,fgets会在末尾自动加上\0;

st[i]='\0';

else //其实是'\0'

while(getchar() != '\n') //会把缓冲区后续的字符都清空

continue;

}

return ret_val;

}

特性:1、会吃进换行符,但是会将其替换成\0空字符;2、会把\0后续的缓冲区内容都清空,为的是不干扰下次输入;

5、scanf()函数

函数原型:int scanf(const char * restrict format,...);

返回一个整数值:该值等于sanf()成功读取的项数或EOF(文件结尾)。文件结尾不存在于文件中,而仅仅是一种标志,流的状态的标志。

scanf("%d %d",&a,&b);

函数返回值为int型。如果a和b都被成功读入,那么scanf的返回值就是2;

如果只有a被成功读入,返回值为1;

如果a和b都未被成功读入,返回值为0;

如果遇到错误或遇到end of file,返回值为EOF。end of file为Ctrl+z 或者Ctrl+d。

++++++++++++++++++++++++++++++++++++++++++++++++++++++

字符串的输出:

1、puts()函数

自动在字符串末尾加上换行符,\n

函数只用来输出字符串,没有格式控制,里面的参数可以直接是字符串或者是存放字符串的字符数组名。

2、fputs()函数

int fputs(const char *str, FILE *stream); ---->向指定的文件写入一个字符串;

str  这是一个数组;

stream 指向FILE对象的指针,该FILE对象标识了要被写入字符串的流。

3、printf()函数

函数的输出格式很多,可以根据不同格式加转义字符,达到格式化输出。

随机推荐

JQ实现判断iPhone、Android设备

最近做了一版微信宣传页,通过JQ来判断设备,并进行下载 微信内置浏览器对下载链接进行了屏蔽,所以先进行判断,如果是微信内置浏览器,则跳转应用宝链接,如果不是,则判断是iPhone/Adroid/PC ...

shell 括号学习

http://blog.csdn.net/tttyd/article/details/11742241 http://tldp.org/LDP/abs/html/loops1.html

【转】Android SDK Manager 更新方法

在Android SDK Manager Setting 窗口设置HTTP Proxy server和HTTP Proxy Port这个2个参数,分别设置为: HTTP Proxy server:mi ...

Mac下搭建quick cocos2d-x编译环境

一. 我知道在你的电脑中一定已经安装好了Xcode(没有自己下载去吧),打开Xcode,开启"偏好设置"对话框(commond + ,).假设打开之后出现的是这种一个对话框,那么直 ...

MySQL show slave status命令参数

? Slave_IO_State SHOW PROCESSLIST输出的State字段的拷贝.SHOW PROCESSLIST用于从属I/O线程.如果线程正在试图连接到主服务器,正在等待来自主服务器的 ...

Delphi 工具条按钮上的下拉菜单

制作步骤: 1.添加一个 TImageList: ImageList1, 然后载入些图标; 2.添加两个 TPopupMenu: PopupMenu1.PopupMenu2, 并分别添加些菜单项; 3 ...

JPA核心类与使用

点击访问:JPA环境配置(一) Persistence: Persistence用于获取EntityManagerFactory实例,这个类中包含一个名为createEntityManagerFact ...

C++对windows控制面板的操作

经常碰到程序无法卸载, 就老是骂微软搞的什么安装方式,安装好了不能卸载. 后来就打算研究一下windows是如何卸载程序的,一个程序安装完后留下了什么信息用于后面的卸载. 研究对象win7 64位, ...

为何time_before 起作用【转】

转自:http://decimal.blog.51cto.com/1484476/410673 Title: jiffies溢出与时间先后比较编制: chinakapok@sina.com日期:200 ...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值