《计算机程式设计》Week6 课堂笔记

本笔记记录自 Coursera课程 《计算机程式设计》 台湾大学 刘邦锋老师

Week6 String

6-1 Character and ASCII

字符变量的声明

char c;

C语言使用一个位元组来储存一个字符,所以一个字符能存一个-128到127之间的整数。

例子:(char-size.c)一个char所占的位元组数

#include <stdio.h>
int main(void)
{
    char c;
    printf("%d\n", sizeof(c));
    return 0;
}

输出

1

字符的输出

printf("%c", c);
  • 字符最大的用处就是以ASCII码的形式将文字讯息显示出来。
  • ASCII码(American Standard Code for Information Interchange),就是将0到127的整数对应到我们常用的英文大小写字母,0到9的数字,以及标点符号等。

例子:(ascii.c)印出部分ASCII码

#include <stdio.h>
int main(void)
{
    char c;
    int i, j;
    printf("0123456789abcdef\n");
    for (i = 2; i <= 7; i++){
        for (j = 0; j <= 15; j++){
            c = i * 16 + j;
            printf("%c", c);
        }
        printf("\n");
    }
    return 0;
}

输出

0123456789abcdef
 !"#$%&'()*+,-./
0123456789:;<=>?
@ABCDEFGHIJKLMNO
PQRSTUVWXYZ[\]^_
'abcdefghijklmno
pqrstuvwxyz{|}~-
  • 这个程序印出由32到127的ASCII码。对应到的16进位数字是20到7F,我们选这个范围是因为32之前的都是特殊字符。
  • 输出是16个字符一行,而且在第一行加上0到f的16进位。

6-2 Character Constant and Integer

  • 字符常数将字符串的ASCII值和它所代表的符号连接起来。
  • C中字符常数是用一对单引号将一个符号括起来,代表它的ASCII值。

例子:(char-assignment.c)将字符常数指定给字符串变量

#include <stdio.h>
int main(void)
{
    char c;
    c = 'm';
    printf("%c", c);
    c = 'a';
    printf("%c", c);
    c = 'i';
    printf("%c", c);
    c = 'n';
    printf("%c", c);
    c = '(';
    printf("%c", c);
    c = ')';
    printf("%c", c);
    c = '\n';
    printf("%c", c);
    c = '{';
    printf("%c", c);
    c = '\n';
    printf("%c", c);
    c = '}';
    printf("%c", c);
    return 0;
}

输出结果

main()
{
}

6-3 Character Input and C-type Functions

字符的输入

scanf("%c", &c);

例子:(char-io.c)输入一个字符分别用字符或整数输出

#include <stdio.h>
int main(void)
{
    char c;
    scanf("%c", c);
    printf("%c\n", c);
    printf("%d\n", c);
    return 0;
}

输入

a

输出

a
97

借由scanf的返回值判定是否还有数据

while (scanf("%c", &c) != EOF){
	...
    process character c;
}

使用字符分类函数

#include <ctype.h>
...
char c;
...
if (isxxxxx(c))

  • 系统的<ctype.h>中定义了一些好用的字符处理函数。
    • 字符分类函数
    • 字符转换函数
  • 字符分类函数决定传进来字符是否属于某一类字符。
    • isalpha(c)会判断c是否为英文字母

字符串分类函数表

函数名称 分类
isalnum 英文字母或数字
isalpha 英文字母
islower 小写英文字母
isupper 大写英文字母
isdigit 数字
isxdigit 16进位数字
isprint 可显示字符(包含空白)
isgraph 可显示字符串(不包含空白)
isspace 空白
ispunct 标点符号
iscntrl 控制字符

6-4 Character Input EOF

在命令行形式下可以打CTRL+D来结束程序。

6-5 ASCII Table in Decimal Format

例子:(ascii-dec.c)用十进位印ASCII表

#include <stdio.h>
int main(void)
{
    int c;
    printf("   0123456789\n");
    for (c = 30; c <= 127; c++){
        if (c % 10 == 0)
            printf("%2d ", c / 10);
        if (isprint(c))
            printf("%c", c);
        else
            printf(" ");
        if (c % 10 == 9)
            printf("\n");
    }
    return 0;
}

输出结果

   0123456789
 3    !"#$%&'
 4 ()*+,-./01
 5 23456789:;
 6 <=>?@ABCDE
 7 FGHIJKLMNO
 8 PQRSTUVWXY
 9 Z[\]^_'abc
10 defghijklm
11 nopqrstuvw
12 xyz{|}~

  • 想输出的范围是32到127可印出的部分。
  • 用isprint()检查是否列印,或是用空白代替。
  • 每一行的开始会印出十进位的前两位。为了对齐,这前两位指定用两位数字印出。方法是在%及d中放一个2。

6-6 Toupper and Tolower Functions

字符转换函数

函数名称 动作
tolower 转成小写英文字母
touppper 转成大写英文字母

6-7 String Declaration

字符串的声明

char s[80];

  • 字符是专门用来处理文字资料的。而文字资料一般都是成批出现的。单独使用字符来处理成批的文字资料很麻烦,所以我们可以使用字符串来处理。
  • C语言以字符数组代表字符串。
  • 字符串的声明就必须制定足够的数组长度,也就是字符串的长度,来储存字符串中的字符。

例子:(string-size.c)字符串所占的记忆体位元组数

#include <stdio.h>

int main(void)
{
    char s[80];
    printf("%D\n", sizeof(s));
    return 0;
}

输出

80

例子:(string-init.c)使用数组的方式初始化一个字符串

#include <stdio.h>

int main(void)
{
    char s[80] = {'m', 'a', 'i', 'n', '(', ')', '\n', '{', '\n', '}', '\n'};
    int i;
    for (i = 0; i < 11; i++)
        printf("%c", s[i]);
    return 0;
}

  • C语言字符串处理的管理是字符串范围到'\0'这个特殊字符为止。这个特殊字符位元组中所有的位元皆为0。

用printf印出字符串

printf("%S", string);

6-8 Empty String

  • 字符串常数和字符常数很类似,只不过字符串常数是用双引号,而字串常数是用单引号
  • printf输出一个整数的参数"%d"就是字符串常数。

例子:(string-init-double-quote.c)使用字符串常数的方式初始化

#include <stdio.h>
int main(void)
{
    char s[80] = "main()\n{\n}\n";
    printf("%s", s);
    return 0;
}

  • 空字符串写成“”
  • 空字符串的第一个字符就是'\0',所以它只占1个位元组。

6-9 String Input

例子:(string-io.c)字符串的输入

#include <stdio.h>

int main(void)
{
    int i;
    char string[10];
    
    while (scanf("%s", string) != EOF){
        printf("%s\n", string);
        for (i = 0; i < 10 && string[i] != '\0'; i++)
            printf("%c ", string[i]);
        printf("\n");
    }
    return 0;
}

  • scanf读字符串遇到空格就会断开,而不是读整行。

6-10 Character Pointer

指向一个字符数组的字符指针也能当字符串

char string[80];
char *ptr = string;

例子:(char-pointer.c)指向一个字符数组的字符指针

#include <stdio.h>
#include <string.h>

int main(void)
{
    char string[80];
    char *ptr = string;
    int i;
    scanf("%s", ptr);
    printf("%s\n", ptr);
    for (i = 0; i < strlen(ptr); i++)
        printf("%c ", ptr[i]);
    return 0;
}

输入

programming

输出

programming
p r o g r a m m i n g

字符指针类别的字符串也可以有初始值

char *string = "programming";

6-11 Strien Usage

  • <string.h>标头档中定义了许多好用的函数,用之前记得要引入。

函数strlen

int strlen(char *string);

  • strlen(string length)计算一个字符串的长度
  • strlen接受一个字符指针参数,这个指针指向要算长度的字串,算出字符串长度并返回。

6-12 Strcpy Strcat

函数strcpy与函数strcat

char *strcpy(char *destination, char *source);
char *strcat(char *destination, char *source);

  • strcpy(string copy)将source参数字符串复制到destination参数字符串,并返回destination的位址。
  • source字符串的结束字符'\0'也会被复制到destination字串。
  • strcat与strcpy类似,但strcat会将第二个字符串参数复制并接到第一个字符串参数的后面。

6-13 Strncpy Strncat

缓冲区覆盖

  • 在使用strcpy及strcat时我们有可能尝试将太长的字符串复制进目的字符串,以致超过目的字符串的长度。
  • 如果目的字符串的后面还有重要的数据,这些数据就会被破坏。这个现象称为缓冲区覆盖(buffer overrun)

函数strncpy与函数strncat

char *strncpy(char *dest, char *source, int i);
char *strncat(char *dest, char *source, int i);

  • strncpy可由第三个参数i控制“至多”要覆盖几个字符,避免缓冲区覆盖。
  • strncpy不会帮你补结束字符'\0',而是要自己加。

例子:(buffer-no-overrun.c)strncpy避免超过长度

#include <stdio.h>
#include <string.h>
int main(void)
{
    char destination[16];
    char source[80];
    printf("destination at %p\n", destination);
    printf("%s", source);
    scanf("%s", source);
    printf("source = %s\n", source);
    strncpy(destination, source, 15);
    destination[15] = '\0';
    printf("source = %s\n", source);
    printf("destination = %s\n", destination);
    reutrn 0;
}

6-14 Strcmp and String Sorting

函数strcmp与函数strncmp

int strcmp(char *string1, *string2);
int strncmp(char *string1, *string2, int n);

  • strcmp比较两个字符串string1及string2的大小。strncmp只比较到n个字符。
    • 如果第一个字符串string1比较小则返回一个负数。
    • 如果第一个字符串string1比较大则返回一个正数。
    • 如果一样大则返回0。
  • 两个字符串的大小比法是由第一个字符开始按ASCII码的大小开始比,如果相同则比第二个字符,直到比出大小或是最后一个字符结束为止。

字符串排序

  • 十二生肖的字符串放在一个二维字符串数组里,第一维代表十二生肖,第二维代表字符串。
  • 使用两层for循环操作泡沫排序法。
    • 第一层循环决定两两交换的范围。
    • 第二层循环实际作两两交换。
  • 使用strcmp比较两个生肖字符串。

例子:(string-sort.c)将字符串排序

#include <stdio.h>
#include <string.h>

int main(void)
{
    char zodiac[12][40];
    int i, j;
    char temp[40];
    
    for (i = 0; i < 12; i++)
        scanf("%s", zodiac[i]);
    
    for (i = 10; i >= 1; i--)
        for (j = 0; j <= i; j++)
            if (strcmp(zodiac[j], zodiac[j + 1]) > 0){
                strcpy(temp, zodiac[j]);
                strcpy(zodiac[j], zodiac[j + 1]);
                strcpy(zodiac[j + 1], temp);
            }
    
    for (i = 0; i < 12; i++)
        printf("%s\n", zodiac[i]);
    return 0;
}

输入

rat
ox
tiger
hare
dragon
snake
horse
sheep
monkey
rooster
dog
pig

输出

dog
dragon
hare
horse
monkey
ox
pig
rat
rooster
sheep
snake
tiger


例子:(string-pointer-sort.c)使用指针数组将字符串排序

#include <stdio.h>
#include <string.h>

int main(void)
{
    char zodiac[12][40];
    char *zptr[12];
    int i;
    int j;
    char *temp;
    for (i = 0; i < 12; i++){
        scanf("%s", zodiac[i]);
        zptr[i] = zodiac[i];
    }
    
    for (i = 10; i >= 1; i--)
        for (j = 0; j<= i; j++)
            if (strcmp(zptr[j], zptr[j + 1]) > 0){
                temp = zptr[j];
                zptr[j] = zptr[j + 1];
                zptr[j + 1] = temp;
            }
    for (i = 0; i < 12; i++)
        printf("%s\n", zptr[i]);
    return 0;
}

6-15 Strtok

函数strtok

char *strtok(char *string, char *delimeters);

  • strtok(string to token)把第一个字符串参数string切成一段一段的token。
  • token是第一个字符串中被第二个字符串参数delimeters中的任何字符所隔开的部分。

例子:(strtok.c)使用strtok将字串切成token

#include <stdio.h>
#include <string.h>

int main(void)
{
    char delimeters[] = "/";
    char pathname[40];
    char file[40][40];
    int file_count = 0;
    char *start = pathname;
    int copy_length;
    int i;
    
    scanf("%s", pathname);
    start = strtok(start, delimeters);
    while (start != NULL){
        strcpy(file[file_count], start);
        file_count++;
        start = strtok(NULL, delimeters);
    }
    for (i = 0; i < file_count; i++)
        printf("%s\n", file[i]);
    printf("After strtok pathname becomes %s\n", pathname);
    return 0;
}

输入

/usr/local/bin/emacs

输出

usr
local
bin
emacs
After strtok pathname becomes /usr

测验代码

自己写的

#include <stdio.h>
#include <string.h>
#include <ctype.h>

int main(void)
{
	char sentence[100][40];
	int i = 0;
	int j;
	int n;
	int start_num = 0;
	int end_num = 0;
	int k;
	int p = 0;
	char output[40];
	
	//输入字符串
	while (scanf("%s", sentence[i]) != EOF)
		i++;
	
	//分割词组,并打印
	for (j = 0; j < i; j++){
		n = strlen(sentence[j])-1;
		if (isalpha(sentence[j][n]))
			end_num++;
		else{
			end_num = j;
			for (k = start_num; k <= end_num; k++)
				if ((strcmp(sentence[k], "of") != 0) && (strcmp(sentence[k], "and") != 0) && (strcmp(sentence[k], "the") != 0) && (strcmp(sentence[k], "at") != 0)){
					output[p]=toupper(sentence[k][0]);
					p++;
				}
			printf("%s ", output);
			strncpy(output, "",p);
			p = 0;
			start_num = j + 1;
			end_num = j + 1;
		}
	}
	
	return 0;
}

老师写的

#include <stdio.h>
#include <ctype.h>
#include <string.h>

int main ()
{
   char str[128];
   int flag = 0;

   while ( scanf ( "%s", str ) != EOF ) {
      if ( flag ) {
         printf ( " " );
         flag = 0;
      }

      if ( strchr ( str, '.' ) )
         flag = 1;
      if ( !strcmp ( str, "and" ) || !strcmp ( str, "at" ) ||
           !strcmp ( str, "of" ) || !strcmp ( str, "the" ) )
         continue;

      printf ( "%c", toupper ( str[0] ) );
   }

   return 0;
}

以及安利一个C的在线编译器,比老师推荐的ideone速度快些,也更清爽些。

C语言在线编译器

posted @ 2018-07-31 22:36  Yingjing  阅读(269)  评论(0编辑  收藏  举报