coursera《计算机程式设计》学习笔记6
2014-10-27 22:02
169 查看
week6
台湾大学 刘邦锋老师讲授1. 字符 character
定义字符变量,字符在C语言中是 char,C 语言中使用一个字节的长度(8位)来存储字符,所以一个字符能存一个 -128 到 127 之间的整数范例2:(char-size.c)一个 char 所占的字节数
#include<stdio.h> int main(void) { char c; printf(" %d\n ", sizeof(c)); //答案是1,即占1个字节的长度 return 0; }
片语3:字符的输出
char c; // <span style="color:#ff0000;">也可以声明成 int c; 因为int 本身包括 4 个字节,存放字符有充足的位置,但不要这样做</span><pre name="code" class="objc">c = 97; // 对应小写字母 a <pre name="code" class="objc">printf(" %c ", c);
ASCII 码,就是将 0 到 127 的整数对应到我们常用的英文大小写字母,0 到 9 的数字,以及标点符号等。
%c 中的 c 代表字符。
2. 字符常数
C 语言中字符常数使用一对单引号将一个符号括起来,代表它的ASCII 值。这样就不需要时刻牢记字符和与之相对应的 ASCII 表中的数字了~#include<stdio.h> int main(void) { char c; c = 'm'; printf(" %c ", c); c = ' \n '; printf(" %c ", c); return 0; }
3. 学习要点
除了表示的范围较小以外,char 的用法与 int 并无太大差别#include<stdio.h> int main(void) { char c; int i; scanf("%d", &i ); //输入 i 为 127 c = i; c++; i++; printf("c = %d\n", c ); printf("i = %d\n", i ); return 0; }
结果输出 c = -128,i = 128。 char 能表示的范围很小,所以很容易溢位overflow
4. 字符的输入
scanf("%c", &c);
范例10:(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
片语11:借由 scanf 的返回值判定是否还有数据未读入
while (scanf("%c", &c) != EOF) { ... process character c; //在循环中对读入的 c 一个接一个进行处理<pre name="code" class="objc">}
在编译环境中程序会自己独到 EOF ,可是在命令行环境的话,当你出入“ab回车”的时候,程序会分别对a、b、回车进行处理,然后不会自动停止,光标会闪闪闪,等待新的输入(ctrl + d 强制停止执行),要怎样才能让程序知道自己读到数据结尾了呢?
在ubuntu linux 系统下直接输入 ctrl + d 就可以了。windows 输入 ctrl + c 即可。
片语12:使用字符分类函数
#include<ctype.h> ... char c; ... if (isxxxxx(c))
系统的 <ctype.h> 中定义了一些函数:字符分类函数、字符转换函数
字符分类函数:
isalnum() 如果参数为字母数字,则返回tureisalpha() 如果参数为字母,则返回ture
islower() 如果参数是小写字母,则返回ture
isupper() 如果参数为大写字母,则返回ture
isdigit() 如果参数为数字(0-9),则返回ture
isxdigit() 如果参数为十六进制数,则返回ture
isprint() 如果参数为打印字符,包括空格,则返回ture
isgraph() 如果参数为空格之外的打印字符,则返回ture
isspace() 如果参数为标准空白字符(空格,进纸,换行符,回车,水平制表符,垂直制表符),则返回ture
ispunct() 如果参数为标点符号,则返回ture
iscntrl() 如果参数为控制字符,则返回ture
范例14:(ascii-dec.c)用十进制来打印ACSII 表
#include<stdio.h> int main(void) { int c; printf(" 0123456789\n"); //前面空了3格 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; }
输出如下:
字符转换函数
tolower() 如果参数为大写字母,即转化为小写字母,否则返回原值toupper() 如果参数为小写字母,即转化为大写字母,否则返回原值
5. 字符串
片语1:定义字符串char s[80];前面的 s 就是一个字符,长度为80个字符的一个字符串,共80 个字节
#include<stdio.h> int main(void) { char s[80]; printf("%d\n", sizeof(s)); return 0; }输出:80
范例3:(string-init.c)使用数组的方式初始化一个字符串
#include<stdio.h> int main(void) { char s[80] = {'m', 'a', 'i', 'n', '(', ')', '\n', '{', '\n', '}', '\n'}; //后面没赋值的地方会自动补 0 int i; for (i = 0; i < 11; i ++) printf("%c", s[ i ]); return 0; }字符串处理惯例:字符串范围到 '\0' 这个特殊字符为止。这个特殊字符的1个字节 8 位 中所有元素都为 0。
片语4:以 printf 打印出字符串
printf("%s", string); // 注意是 %s
所以,在范例3 中的程序中 ,可以改写成:
<pre name="code" class="objc">#include<stdio.h> int main(void) { char s[80] = {'m', 'a', 'i', 'n', '(', ')', '\n', '{', '\n', '}', '\n','\0'}; //在字符串后面自己手动加 一个 '\0',使打印的时候遇到它就停止 int i; printf("%s", s) // 不需要知道字符串长度<pre name="code" class="objc"> return 0;
}
6. 字符串常数
范例6:(string-init-double-quote.c)使用字符串常数的方式初始化#include<stdio.h> int main(void) { char s[80] = "main()\n{\n}\n"; printf("%s", s); return 0; }字符串的最后面会加一个 '\0' 字元,会自动帮补的,无需自己补。
空字符串
是一个特别的字符串常数,写成 “”。空字符串的第一个字符就是 '\0',所以它只占1个 字节
7. 字符串读入
char string[10];<pre name="code" class="objc">scanf("%s", string); //由于string本身可以代表地址位置,所以不需要加 & 取址符号,字符串中间 无空格 无换行 无Tab等,无以上东西的才会被读到一个 string 里面去
8. 字符指针
片语9:指向一个字符数组的字符指针也能当字符串char string[80]; // 定义字符串 char *ptr = string; //指针一开始指向 字符串 的开头
范例10:(char-pointer.c)指向一个字符数组的字符指针
#include<stdio.h> #include<string.h> int main(void) { char string[80]; char *ptr = string; //指针指向了 string 的开头,ptr和string 就已经是存的同样的地址了。
int i; scanf("%s", ptr); //写 ptr 和 写 string 都是把 字符串 放到 string 里头 printf("%s\n", ptr); for (i = 0; i < strlen(ptr); i++) printf("%c ", ptr[i]); //如果最开始 ptr 没有知道string的开头部分,而是指到了其他部分,那么 ptr[i]所代表的东西就不太一样,可以做动态调整 return 0; }输入:programming
输出:programming
p r o g r a m m i n g
片语11:字符指针这种类别的字符串也可以赋初始值
char *string = "programming"; //这个字符数组是不能改的编译器会在 只读存储器
中放一个字符数组,初始化成 “programming”,再将 string 指向这个 字符数组
三种字符串
范例12:(char-pointer-init.c)三种字符串#include<stdio.h> #include<string.h> int main(void) { char str1[80] = "programming"; //如果要打印 str1[88] 这种也是可以打印的 char str2[] = "programming"; // 如果要打印 str2[28] 这种也是可以打印的 char *str3 = "programming"; printf("sizeof(str1) = %d\n", sizeof(str1));<pre name="code" class="objc"> printf("sizeof(str2) = %d\n", sizeof(str2));<pre name="code" class="objc"> printf("sizeof(str3) = %d\n", sizeof(str3));<pre name="code" class="objc"> printf("strlen(str3) = %d\n", strlen(str3));<pre name="code" class="objc"> return 0;<pre name="code" class="objc">}
输出:
sizeof(str1) = 80
sizeof(str2) = 12
sizeof(str3) = 8 //char *string3 本身是指针,只占8个字节。 我在自己的编译器上,是占了4个字节。
strlen(str3) = 11
9. 常用函数
函数原型14:strlen
int strlen(char *string); // 并不包括最后的 '/0',只计算了前面的长度
范例16:(my-strlen.c)自己做 strlen
#include<stdio.h> int my_strlen(char *string) { int i = 0; while(i < 80 && string[i] != '\0') i++; return i; } int main(void) { int length; char string[80]; scanf("%s", string); printf("%s\n", string); length = my_strlen(string); printf("%d\n", length); return 0; }
长度 <= 80 的字符串都可以计算长度( = 80 的时候会出现 debug error ,但是可以得到正确答案 : 80 )
函数原型 18:(strcpy-strcat)
char *strcpy(char *destination, char *source) char *strcat(char *destination, char *source)
strcpy(string copy)复制,source字符串结尾的 '\0' 也会被复制到 destination 字符串
strcat (string concatenation)接尾巴,将第二个字符串复制并接到第一个字符串的后面
范例 19:(string-copy.c)strcpy
#include<stdio.h> #include<string.h> int main(void) { char source[100]; char destination[100]; scanf("%s", source); scanf("%s", destination); printf("%s\n", destination); strcpy(destination, source); printf("%s\n", destination); return 0; }输入:source
destination
输出:destination
source
范例 20:(string-concat.c)strcat
#include<stdio.h> #include<string.h> int main(void) { char source[100]; char destination[100]; scanf("%s", source); scanf("%s", destination); printf("%s\n", destination); strcat(destination, source); printf("%s\n", destination); return 0; }
输入:source
destination
输出:destination
destinationsource
注:如果 copy 的时候,source过长,destination不够长,这种情况叫做buffer overrun。source里超出长度的数据就会被破坏。
范例 21:(buffer-overrun.c)
#include<stdio.h> #include<string.h> int main(void) { char destination[16]; char source[80]; printf("destination at %p\n", destination); printf("source at %p\n", source); scanf("%s", source); printf("source = %s\n", source); strcpy(destination, source); printf("source = %s\n", source); printf("destination = %s\n", destination) return 0; }输入:
bufferoverrunwillhappen
输出:
destination at 0x7fffc72762d0
source at 0x7fffc72762e0
source = bufferoverrunwillhappen // 截止到will 的第一个 l 之后,是16 个字符
source = lhappen // 由于destination 和 source 的地址是接着的,所以在destination 里存放不下的字符就会继续存放在地址紧接的 source里,并且带着source字符串里的 '\n',所以source只引出了lhappen。
destination = bufferoverrunwillhappen
函数原型 22:(strncpy-strncat)
char *strncpy(char *dest, char *source, int i);char *strncat(char *dest, char *source, int i);
注:strncpy 可由第 3 个参数 i 控制“至多”要复制几个字节的数据,避免缓冲区覆盖
strncpy 不会自动补充结束字符 '\0', 而是要自己手动添加
范例 23:(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("source at %p\n", 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)
return 0;
}输入:
bufferoverrunwillhappen.
输出:
destination at 0x7fff30ebe3e0
source at 0x7fff30ebe3f0
source = bufferoverrunwillhappen.
source = bufferoverrunwillhappen.
destination = bufferoverrunwi
函数原型 25:(strcmp-strncmp)
int strcmp(char *string1, *string2);int strncmp(char *string1, *string2, int n);
strcmp:比较两个字符串的大小
strncmp:只比较到第 n 个字节
如果string1 较小,则返回负数
如果string1 较大,则返回正数
如果一样大,则返回 0
比较方法:由第一个字符开始按照 ACSII码的大小开始比较,如果相同则比较第二个字符,知道比出大小或者其中一个字符串结束为止。
范例 26:(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--) //冒泡排序法,第一轮是1和2比,2和3比,一次类推,把最大的数推至第11位上去。第二轮把最大的数推至第10位上去...
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;
}
范例 27:(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]; //省去 strcpy 的时间
zptr[j+1] = temp;
}
for (i = 0; i < 12; i++)
printf("%s\n", zptr[i]);
return 0;
}
函数原型 28:(strtok)
char *strtok(char *string, char *delimeters)
strtok (string to token)把第一个字符串参数 string 切成一段一段的 token
token 是第一个字符串中 被第二个字符串参数 delimeters 中的任何字符 所隔开的部分
片语 29: strtok
start = strtok(string, delimeters); while (start != NULL) { process string at start; start = strtok(NULL, delimeters); }
範例 30: (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); // strtok 的固定使用形式 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; }
如果分割符发生变化,就像这样:
char delimeters[] = "aeiou";
其他代码不变,结果为:
相关文章推荐
- coursera《计算机程式设计》学习笔记1
- coursera《计算机程式设计》学习笔记2
- Coursera课程《Machine Learning》学习笔记(week1)
- Coursera课程《Machine Learning》学习笔记(week1)
- Coursera课程《Machine Learning》学习笔记(week2)
- 《软件调试的艺术》学习笔记——GDB使用技巧摘要
- 神经网络与深度学习编程练习(coursera 吴恩达 )(3)
- ES5中 array操作 菜鸟学习笔记
- 《Machine Learning》学习笔记(4)–线性模型
- 《编程之美》学习笔记——2.3寻找发贴“水王”
- [整理] 解决 Coursera 视频无法播放
- 《Linux高性能服务器编程》学习笔记——第五章 Linux网络编程基础API(2)
- 学习笔记(11月06日) --类
- 《Linux高性能服务器编程》学习笔记——第七章 Linux服务器程序规范
- 炼数成金CUDA视频教程——第三课1——学习笔记
- 《编程之美》学习笔记——2.21只考加法的面试题
- ** 文件操作与模板 编程题#4: 字符串操作(Coursera 程序设计与算法 专项课程3 C++程序设计 郭炜、刘家瑛;OpenJudge)
- Coursera-Getting and Cleaning Data-Week3-dplyr+tidyr+lubridate的组合拳
- python3.5《机器学习实战》学习笔记(五):决策树算法实战之预测隐形眼镜类型
- 《精通CSS与HTML设计模式》学习笔记2