《C primer plus》笔记:字符串

20180606 qzd


1. 表示字符串和字符串IO


#define MSG = "hello world!";
char a[MAX] = "hello world!";
char * p = "hello world!";
puts(MSG);
puts(a);
puts(p);

2. 定义字符串


  • 字符串字面量:双引号括起来的内容,编译器会自动加入\n,双引号之间紧邻或者空格看作相连的
char * a = "hello " "world!";  //  hello world!

函数中使用字符串,只存储一次,被视为指向该字符串位置的指针

printf("%s, %p, %c\n", "hello", "world", *"ok"); // hello,0X000000999,o
  • 字符串数组:和字符数组区别,两种初始化方式
char a[40] = "sadasfsdfgsdgfdgfdhfdh";    //简易初始化
char a[40] = {'a','b','c'...'g', '\n'}    //标准初始化
char a[] = "dsfsdfsdfdsfsdfsdf";          //编译器自动计算长度
const char * a = "sdsafsdfsdfsdfsfdf";          //同上
//定长初始化中未被初始化的部分填充'\0'
  • 数组形式与指针形式区别

数组形式的a == &a[0] 只能作为常量,不能进行a ++等操作,指针形式a 是可以进行a ++的
指针对数据类型匹配很高,指向常量的指针需要被声明为常量const char * p = “abc”;
意味着不能用p改变数据的值,但可以改变p的位置
初始化数组把静态存储区的字符串拷贝给数组,初始化指针只是把字符串的地址给指针

  • 字符串与数组
//相当于字符的二维数组
char f[3][4] = {{"ab"},{"cd"},{"e"}};  // ab\0, cd\0, e\0\0
//相当于3个字符串指针
const char * p[3] = {{"ab"},{"cd"},{"e"}}; // ab\0, cd\0, e\0 自动获取大小
  • 字符串与指针:指针拷贝也只拷贝地址,没有拷贝整个字符串

3. 字符串输入


  • 分配空间:用显示声明来输入,否则会丢失数据
char *name; scanf("%s", name);   //不好
char name[SIZE]; scanf("%s", name); //可以的
  • gets()函数:已废弃,并不知道字符串有多长,输入字符过长导致缓冲区溢出,可能导致其他数据被擦除
#include 
int main(void){
 char name[10];
 gets(name);
 puts(name);
 return 0;
}
//gcc 编译没报任何消息
//fgdfgdfgdfgfdgfdg
//fgdfgdfgdfgfdgfdg

实际情况:大多数编译器仍支持

  • fgets()函数:可以替代gets(),可扩展,可以从文件输入,保留换行符,需要手动设置为空字符
    • 读一行:读到换行或者读到n个字符,最终打印的n-1个字符
#include 
int main(void){
         char a[10];
         fgets(a, 7, stdin);  //读了dsfdsf个字符+'\0'
         fputs(a, stdout);    //输出dsfdsf\0 没有+'\n' 
         return 0;
}
//dsfdsfsdgfdgdffdg 
//dsfdsf
    • 连续读取,fgets可以存储换行符,读完一段,继续读剩下的,可以直接读到文件尾部
#include 
#define N 10
int main(void){
         char word[N];
         while( fgets(word, N, stdin) != NULL && word[0] != '\n' ){
         fputs(word, stdout);
         }
         return 0;
}
    • 每行只读一定数量的字符,并丢弃了换行符
#include 
#define N 10
int main(){
 char word[N];
 int i;
 while( fgets(word, N, stdin) != NULL && word[0] != '\n'){
 i = 0;
 while(word[i] != '\n' && word[i] != '\0')
 i++;             //不是换行符或者空字符跳过
 if(word[i] == '\n')
 word[i] = '\0'; //遇到换行符,转空字符
 else
 while(getchar() != '\n') //读到空字符,丢弃剩余
 continue;
 fputs(word, stdout);
 }
 return 0;
}

空字符于空指针:空字符(‘\0’)与空指针(NULL)都可以用0表示,但空字符是字符型(1字节),空指针是指针型(4字节)

  • gets_s()函数:c11新增,可扩展,只从标准输入中输入,丢弃换行符,输入太长时更安全
  • s_gets()函数:fgets()变体,遇到换行符设为空,遇到空丢弃其余字符
  • scanf()函数:可指定宽度,但遇空格即终止,只能用于输入单词

4. 字符串输出


  • puts()函数:使用字符串地址作参数,自动添加换行符
  • fputs()函数:用于文件输出,不添加换行符,遇fgets()配对使用
  • printf()函数:不自动加换行符,打印多个字符更简单

5. 自定义输入输出


6. 字符串函数


(类型)函数名 参数 作用
int strlen char * 统计字符串长度
char * strcat char , char 把第二个字符串拼接在第一个上
char * strncat char *, char *, int 把第二个字符串指定长度添加到第一个字符串上
int strcmp char , char 比较两个字符串,相同返回0,二大于1返回正,否则返回负
int strncmp char *, char *, int 限定比较的字符串长度
char * strcpy char , char 把第二个拷贝到第一个
char * strcpy char *, char *int 限制拷贝的字符串长度
void sprintf char *, 格式化, name 将printf的内容存储在一个字符串中

7. 字符串排序


  • 示例
#include 
#include 
#define SIZE 81  //字符串长度
#define LIM 20   //最大行数
#define HALT ""  //读到空字符结束
void strSort(char * str [], int num); //排序函数
char * strGets(char * , int );    //输入字符串函数

int main(void){
 char in[LIM][SIZE];
 char * pstr[LIM];
 int ct = 0, k = 0; //输入输出计数
 while(ct < LIM && strGets(in[ct], SIZE) != NULL && in[ct][0] != '\0'){
 pstr[ct] = in[ct];
 ct++;          //输入字符串
 }
 strSort(pstr, ct); //排序字符串
 for(k = 0; k < ct; k++)
 puts(pstr[k]); //输出字符串
 return 0;
}
//选择排序
void strSort(char * str [], int num){
 char *temp;
 int top, seek;
 for (top = 0; top < num-1; ++top)
 {
 for (seek = top + 1; seek < num; ++seek)
 {
 if( strcmp(str[top], str[seek]) > 0 )
 temp = str[top];
 str[top] = str[seek];
 str[seek] = temp; 
 }
 }
}
//自定义输入函数
char * strGets(char * str, int n){
 char * ret_val;
 int i = 0;
 ret_val = fgets(str, n, stdin);
 if(ret_val){
 while(str[i] != '\n' && str[i] != '\0')
 i++;
 if(str[i] == '\n')
 str[i] = '\0';
 else
 while(getchar() != '\n')
 continue;
 }
 return ret_val;
}
  • 排序单位是指针:排序的是指针而不是字符串本身
  • 选择排序算法
//伪代码
for n = 首元素 to n=倒数第2个元素
 找出剩余元素中的最大元素,并将其放在第n个元素
//C代码
for(top = 0; top < n - 1; top++)
 for(seek = top + 1; seek < n; seek++)
 if(a[top] > a[seek])
 swap(&a[top], &a[seek]);

8. 字符串和ctype.h字符函数


9. 命令行参数:int argc, char *argv[]


int main(int argc, char *argv[])
{
 argc // 命令行字符串数量
 argv // 字符串数组指针 argv[n] 表示第n个字符串的地址
}
#include 
int main(int argc, char * argv[]){
 int i = argc;
 printf("%d\n", argc);
 while( i-- >  1 ) 
 puts(argv[i]);
}
// --i情况  (没想到argc = 4)  (- -)
// test86 see you later  0 1 2 3 
// 1) (i = 4- 1 = 3, i > 0) -> a[3]
// 2) (i = 3- 1 = 2, i > 0) -> a[2]
// i--情况
// 1) (i = 4 > 0, i = 3 - 1 = 2) -> a[3]
// 2) (i = 3 > 0, i = 2 - 1 = 2) -> a[2]
// 3) (i = 2 > 0, i = 1 - 1 = 1) -> a[1]

10. 字符串转数字


void reStr(char * a, int n){
 int i = 0;
 char b[n];
 while(i++ < n)
 b[i] = a[i-1];
 i = 0;
 while(n-- >= 0){
 a[i] = b[n];
 i++;
 }
}
  • 小训练:命令行输出
#include 
#include 
#define N 10
void pf(char * , int);
void toUpper(char * , int);
void toLower(char * , int);
int main(int argc, char * argv[]){
 char a[N];
 switch (argv[1][1]){
 case 'p': pf(a, N); break;
 case 'u': toUpper(a, N); break; 
 case 'l': toLower(a, N); break;
 default : puts("enter error!"); break;
 }
 return 0;
}
//原样输出
void pf(char * a, int n){
 while( fgets(a, n, stdin) != NULL && a[0] != '\n'){
 fputs(a, stdout);
 }

}
//输出大写
void toLower(char * a, int n){
 int i;
 while( fgets(a, n, stdin) != NULL && a[0] != '\n'){
 i = 0;
 while(i++ < n-1){     // i=0<9 i=1 a[0], i=1<9 i=2 a[1] ---> i=8<9 i=9 a[8]
 if(isupper(a[i-1]))
 a[i-1] = tolower(a[i-1]);
 }
 fputs(a, stdout);
 }
}
//输出小写
void toUpper(char * a, int n){
 int i;
 while( fgets(a, n, stdin) != NULL && a[0] != '\n'){
 i = 0;
 while(i++ < n-1){
 if(islower(a[i-1]))
 a[i-1] = toupper(a[i-1]);
 }
 fputs(a, stdout);
 }
}

参考:https://suoyuesmile.github.io/2015/07/06/c4/

你可能感兴趣的:(《C primer plus》笔记:字符串)