字符串与字符串函数 - 字符串 & 字符串输入

一、表示字符串与字符串I/O

  【字符串 - 以空字符(\0)结尾的 char 类型数组】

  1、字符串字面量(字符串常量)

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

  ANSI C 标准规定,如果字符串常量之间没有间隔,或者用空白字符分隔,C 会将其视为串联起来的字符串常量。

char chr1[50] = "Hello, and""how are" " you"
                     " today!";
char chr2[50] = "Hello, and how are you today!";    //chr1 与chr2 中存储的内容一致

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

  字符串常量属于静态存储类别(static storage class),这说明如果在函数中使用字符串常量,该字符串只会被储存一次,在整个程序的生命周期内存在,即使函数被调用多次。

  2、字符串数组的初始化

  定义字符串数组时,必须让编译器知道需要多少空间。

  可以在初始化数组的时候顺便填充数组,也可以先初始化,之后再填充。不管如何,初始化的时候,数组的大小对于编译器来说,是必须要确定的。

  3、数组与指针的区别

  初始化数组:把静态存储区的字符串拷贝到数组中;初始化指针:只把字符串的地址拷贝给指针。

#define MSG "I‘m special!"
#include <stdio.h>

int main(void) {
    char ar[] = MSG;
    const char * pt = MSG;
    printf("address of \"I‘m special!\": %p \n", "I‘m special!");
    printf("        address ar: %p \n", ar);
    printf("        address pt: %p \n", pt);
    printf("        address of MSG: %p \n", MSG);
    printf("address of \"I‘m special!\": %p \n", "I‘m special!");
    return 0;
}

  

  通过上述的结果我们知道:

  第一,pt 和 MSG 的地址一样,而 ar 的地址不同;

  第二,虽然字符串自变量“I‘m special” 在程序的两个 printf() 函数中出现了两次,但是编译器只使用了一个存储位置,而且与 MAG 的地址相同,编译器可以把多次使用的相同字面量储存在一处或多处。也有的编译器会在不同的位置存储三个“I‘m special”;

  第三,静态数据使用的内存与 ar 使用的动态内存不同,不仅值不同,特定编译器甚至使用不同的位数来表示两种内存。

char heart[] = "Hello!";
const char * head = "Hello!";

  首先,heart 是常量名,head 是变量。其两者之间的区别如下:

  第一,两者都可以使用数组表示法【heart[i] 、head[i]】;

  第二、两者都能进行指针加法操作【*(heart + 1) 、*(head + 1)】;

  第三、只有指针可以进行递增操作;

  第四、可以通过 heart 改变数组中元素的信息。

二、字符串输入

  1、gets() 函数

#define STLEN 50
...
char words[STLEN];
...
gets(words);    //典型用法
...
puts(words);
...

  函数功能:读取整行输入直至遇到换行符,然后丢弃换行符,储存其余字符,并在这些字符的末尾添加一个空字符使其成为一个 C 字符串。经常和 puts() 函数配对使用【puts() 函数会在待输出字符串末尾添加一个换行符】。

  问题:gets() 函数只知道数组的开始处,并不知道数组中具体有多少个元素。如果输入的字符串过长,会导致缓冲区溢出(buffer overflow),即有多余的字符超出了指定的目标空间。如果这些多余的字符只是占用了那些尚未使用的内存,就不会立即出现问题;如果擦写程序中的其他数据,会导致程序异常终止;或者还有其他的情况。在 UNIX 系统中,“Segmentation fault”说明当前程序视图访问未分配的内存。

  【C99 、C11 标准不建议使用该函数】

  2、fgets() 函数

#define STLEN 14
...
char words[STLEN];
...
fgets(words, STLEN, stdin);
...
fputs(words, stdout);
...

  fgets() 函数与 gets() 函数之间的区别如下:

  第一,fgets() 函数的第 2 个参数指明了读入字符的最大数量,如果该参数是 n ,那么 fgets() 函数将读入 n - 1 个字符,或者读到遇到第一个换行符为止;

  第二,如果 fgets() 函数读到一个换行符,会把它储存在字符串中,gets() 函数会丢弃换行符;

  第三,fgets() 函数的第3个参数指明要读入的文件,如果读入的是从键盘输入的数据,则以 stdin (标准输入)作为参数,该标识符定义在 stdio.h 中;与 fputs() 函数配套使用【fputs() 函数的第 2 个参数指明其需要写入的文件,如果要在显示器上进行显示,应使用 stdout(标准输出)作为参数进行传递】【fputs() 函数不会在待输出字符串末尾添加一个换行符】。

#define STLEN 10
#include <stdio.h>

int main(void) {
    char words[STLEN];

    puts("Enter string (empty line to quit):");
    while (fgets(words, STLEN, stdin) != NULL && words[0] != ‘\n‘)
        fputs(words, stdout);
    puts("Done.");

    return 0;
}

  在上述的例子中,虽然字符串的长度被限制在了10以内,但是从结果上来看,长字符串的输入并没有受到明显的影响。

  【在程序中,fgets() 函数一次读入 STLEN - 1 个字符,即第一次只读入了“By the wa”,存储在 words 数组中的内容为‘By the wa\0’,接着 fputs() 函数打印该字符串,且没有换行;然后 while 循环进入下一轮迭代, fgets() 函数继续从剩余的输入中读取数据,即读入“y, the ge”,并存储为 y, the ge\0,接着 fputs() 函数在刚才打印字符串的这一行接着打印第2次读入的字符串;继续循环,直到读入最后的“tion\n”,fgets() 将其存储为 tion\n\0,fputs()函数将其输出,由于字符串中的 \n,光标被移至下一行开始处。】

  【系统使用缓存 I/O,在用户键入 ENTER 键之前,输入的内容都会被存储在临时存储区(即,缓存区)中。键入 ENTER 键之后,在输入缓存区中增加一个换行符,并把整行输入发送给 fgets() 函数。fputs() 函数把字符发送给另一个缓冲区,当发送换行符时,缓冲区中的内容被发送至屏幕上。】

  【空字符与空指针:概念上来说,空字符(或‘\0’)是用于标记 C 字符串末尾的字符,其对应字符编码是0,由于其他字符的编码不可能是0,所以不可能是字符串的一部分;空指针(或NULL)有一个值,该值不会与任何数据的有效地址对应,通常,函数使用其返回一个有效地址表示某些特殊情况的发生,例如遇到文件结尾或未能按预期执行。空字符是整数类型,是一个字符,占一个字节,而空指针是指针类型,是一个地址,通常占4字节。】

  3、gets_s() 函数

  gets_s() 函数与 fgets() 函数类似,用一个参数限制读入的字符数。

gets_s(words, STRLEN);

  gets_s() 与 fgets() 的区别:1 - gets_s() 函数只从标准输入中读取数据,所以不需要第 3 个参数;2 - 如果 gets_s() 函数读取到换行符,将丢弃换行符,而不是继续存储换行符;3 - 如果 gets_s() 函数读到最大字符数的时候都没有读取到换行符,则进行以下操作【1,把目标数组中的首字符设置为空字符,读取并丢弃随后的输入直到读到换行符或文件结尾;2,返回空指针;3,调用依赖实现的“处理函数”(或自己选择的其他函数),可能会中止或退出程序。】。

  【总结:1 - 如果输入行未超过最大字符数,gets_s()、gets()、 fgets() 三函数没有太大区别,只不过 fgets() 函数会保留输入末尾的换行符作为字符串的一部分;2 - 如果输入行太长,gets() 函数并不安全,会擦写现有数据,存在安全隐患,gets_s() 函数虽然较为安全,但是并不希望程序的中止或退出。 】

  4、sacnf() 函数

  scanf() 函数更像是“获取单词”的函数,而不是“获取字符串”的函数。

  scanf() 函数的典型用法是读取并转换混合数据类型为某种标准格式。【输入行过长,可能也会导致 scanf() 函数读取溢出,但是,在 %s 转换说明中指定字段宽度可在一定程度上解决该问题。】

原文地址:https://www.cnblogs.com/wyt123/p/11042397.html

时间: 2024-10-10 19:17:44

字符串与字符串函数 - 字符串 & 字符串输入的相关文章

40 python 正则表达式 match方法匹配字符串 使用search函数在一个字符串中查找子字

第一课: 使用match方法匹配字符串 # 正则表达式:使用match方法匹配字符串 ''' 正则表达式:是用来处理文本的,将一组类似的字符串进行抽象,形成的文本模式字符串 windows dir *.txt file1.txt file2.txt abc.txt test.doc a-file1.txt-b linux/mac ls 主要是学会正则表达式的5方面的方法 1. match:检测字符串是否匹配正则表达式 2. search:在一个长的字符串中搜索匹配正则表达式的子字符串 3. fi

实现字符串检索strstr函数、字符串长度strlen函数、字符串拷贝strcpy函数

1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 5 /* 6 _Check_return_ _Ret_maybenull_ 7 inline char* __CRTDECL strstr(_In_z_ char* const _String, _In_z_ char const* const _SubString) 8 { 9 return const_cast<char*>

43 正则中用sub和subn函数搜索与替换 使用split函数分隔字符串 练习题

第10课 正则中用sub和subn函数搜索与替换 # 使用sub和subn函数搜索和替换 ''' sub(正则表达式,要替换的字符串,母字符串) ''' import re result = re.sub('Bill','Mike', 'Bill is my son.') print(result) # Mike is my son. 把Bill 替换成 Mike result = re.subn('Bill', 'Mike', 'Bill is my son, I like Bill') pr

谭浩强 C程序设计 8.5 写一个函数,使输入的一个字符串按返序存放

写一个函数,使输入的一个字符串按返序存放,在主函数中输入和输出字符串. #include <stdio.h> #include <string.h> int main(){ void reverse(char arr[]); char arr[50]; gets(arr); reverse(arr); for(int i=0; i< strlen(arr); i++){ printf("%3c",arr[i]); } printf("\n&quo

gets()、puts()函数。字符串函数。字符串排序的例子。

1.实例程序:string.c的程序: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include<stdio.h> #define MSG "YOU MUST have many talents .tell me some." #define LIM 5 #define LINELEN 81 int main() { char name[LINELEN]; char

关于C中scanf()函数读取字符串的问题

1 #include <stdio.h> 2 3 int main(void) 4 { 5 char s_name[20]; 6 7 scanf("%s", s_name); 8 printf("Hello, %s!\n", s_name); 9 10 return 0; 11 } 对于这段简单的代码,如果输入一个名字如:Stephen,很容易知道,其输出为: Hello, Stephen! 这个很容易理解,但是输入更完整的名字如:Stephen Pra

SQLSERVER常见系统函数之字符串函数(一)

好久没有写博客了,这段时间准备写一下字符串函数 QQ群: 499092562:欢迎交流 字符串函数: 1.LEN(需要获取长度的字符串) 返回:字符串的长度 示例: SELECT LEN('小搬运工很帅!') 2.RIGHT(需要被从右边截取的字符串,截取的开始下标,截取的长度) 返回:右边的字符串 示例: SELECT RIGHT('小搬运工',2,2) ‘小搬运工’从右边数第二个下标开始,长度为二的字符串 3.CHARINDEX(父字符串,需要查找位置的子字符串,从哪个位置开始找) 示例:S

JavaScript字符串常用操作函数之学习笔记

字符串简介 使用英文单引号或双引号括起来,如:’Hello’,”World”,但是不能首尾的单引号和双引号必须一致,交错使用,如果要打印单引号或者双引号,可以使用转义字符\’(单引号),\”(双引号)  代码如下 复制代码 var str_1 = 'Hello World!';  //Hello World!var str_2 = "Hello World!";  //Hello World!var str_3 = '他说:"这样可以的."';  //他说:&quo

c++实现atoi()和itoa()函数(字符串和整数转化)

  c++实现atoi()和itoa()函数(字符串和整数转化) 一:起因 (1)字符串类型转化为整数型(Integer),还是字符串类型(String)转化为Double类型,这在java里面有非常好的内部函数,很easy的事情: (2)但是在c里面没有Integer Double等包装类,由char[]数组转化为整数型就变得不那么简单了,atoi()  itoa()在widows下面有,但是网上说linux 下好像没有 itoa() 函数,用 sprintf() 好了,但是本人测试了一下sp

ORACLE常用数值函数、转换函数、字符串函数

本文并不准备介绍全部的oracle函数,当前情势下,俺也还没这个时间,需要学习的东西太多了,要把多数时间花在学习经常能用上的技术方面:),所以如果是准备深入了解所有oracle函数的朋友,还是去关注:Oracle SQL Reference官方文档更靠谱一些. 本文更多将会介绍三思在日常中经常会用到的,或者虽然很少用到,但是感觉挺有意思的一些函数.分二类介绍,分别是: 著名函数篇 -经常用到的函数 非著名函数篇-即虽然很少用到,但某些情况下却很实用 注:N表示数字型,C表示字符型,D表示日期型,