1.1 入门
学习一门新程序设计语言的唯一途径就是使用它编写程序,我们第一个C语言程序:
#include <stdio.h>
main()
{
printf("hello world\n");
}
程序简单的一些说明:一个C语言程序,无论其大小如何,都是由函数和变量组成的。函数中包含一些语句,以指定所要执行的计算操作;变量则用于存储计算过程中使用的值。通常情况下,函数的命名没有限制,但main是一个特殊的函数名---每个程序都从main函数的起点开始执行,这意味着每个程序都必须在某个位置包含一个main函数。
用双引号括起来的字符序列称为“字符串”或者“字符串常量”,而“\n”称为转义字符。
习题1-1,习题1-2略过。
1.2 变量与算数表达式
#include <stdio.h>
/* 当fahr = 0,20,...,300时,
分别打印华氏温度与摄氏度对照表
*/
main()
{
int fahr, celsius;
int lower, upper, step;
lower = 0;
upper = 300;
step = 20;
fahr = lower;
while (fahr <= upper){
celsius = 5 * (fahr - 32) / 9;
printf("%d\t%d\n", fahr, celsius);
fahr = fahr + step;
}
}
1. 用/**/分割起来的是注释,它可以用于简单的用于解释程序,使程序更易阅读。
2. 所有变量必须先声明后使用。声明用于说明变量的属性,它由一个类型名和一个变量表组成。
3. 良好的编程习惯是:每行只写一条语句,并在运算符两边各加上一个空格字符。
为了更加精确的计算温度,我们需要将整型数替换为浮点数:
#include <stdio.h>
/* 当fahr = 0,20,...,300时,
分别打印华氏温度与摄氏度对照表
*/
main()
{
float fahr, celsius;
int lower, upper, step;
lower = 0;
upper = 300;
step = 20;
fahr = lower;
while (fahr <= upper){
celsius = (5.0 / 9.0) * (fahr - 32.0);
printf("%3.0f\t%6.1f\n", fahr, celsius);
fahr = fahr + step;
}
}
1. 就算浮点型常量取值整型,也要加上一个小数点,强调浮点性质。
2. printf的一些格式:%o表示八进制数;%x表示十六进制数;%c表示字符;%s表示字符串;%%表示百分号(%)本身。
习题1-3:
#include <stdio.h>
/* 当fahr = 0,20,...,300时,
分别打印华氏温度与摄氏度对照表
*/
main()
{
float fahr, celsius;
int lower, upper, step;
lower = 0;
upper = 300;
step = 20;
printf("华氏温度转换为摄氏度\n");
fahr = lower;
while (fahr <= upper){
celsius = (5.0 / 9.0) * (fahr - 32.0);
printf("%3.0f\t%6.1f\n", fahr, celsius);
fahr = fahr + step;
}
}
习题1-4:
#include <stdio.h>
/* 当fahr = 0,20,...,300时,
分别打印摄氏度与华氏温度对照表
*/
main()
{
float fahr, celsius;
int lower, upper, step;
lower = 0;
upper = 300;
step = 20;
printf("摄氏度转换为华氏温度\n");
celsius = lower;
while (celsius <= upper){
fahr = 32.0 + 9.0 / 5.0 * celsius;
printf("%6.1f\t%3.1f\n", celsius, fahr);
celsius = celsius + step;
}
}
程序输出:
习题1-5:
#include <stdio.h>
main()
{
float fahr, celsius;
int lower, upper, step;
lower = 0;
upper = 300;
step = 20;
fahr = upper;
while (fahr >= lower){
celsius = (5.0 / 9.0) * (fahr - 32.0);
printf("%6.1f\t%3.1f\n", celsius, fahr);
fahr = fahr - step;
}
}
程序输出:
1.4 符号常量
使用幻数0,300,20并不是好的编程习惯,我们可以通过符号常量(宏定义)方式改写程序:
#include <stdio.h>
#define LOWER 0
#define UPPER 300
#define STEP 20
main()
{
int fahr;
for (fahr = LOWER; fahr <= UPPER; fahr += STEP){
printf("%3d\t%6.1f\n", fahr, (5.0 / 9.0) * (fahr - 32.0));
}
}
1.5 字符输入/输出
标准库提供的输入/输出模型非常简单。无论文本从何处输入,输出到何处,其输入/输出都是按照字符流的方式处理。文本流是由多行字符构成的字符序列,而每行字符则由0个或多个字符组成,行末是一个换行符。
最基本的输入输出函数为:getchar()--读取单个字符,putchar(c)--打印字符c。
1.5.1 文件复制
#include <stdio.h>
main()
{
int c;
c = getchar();
while (c != EOF){
putchar(c);
c = getchar();
}
}
程序输入输出如下:
1. 这里c之所以声明为int而不是char,是因为我们要保证能够存储任何字符外还能存储特殊字符EOF(end of file).
2. c = getchar()之类的赋值操作是一个表达式,并且具有一个值,即赋值后左边变量保存的值。所以代码可以进行类似的简洁修改:
#include <stdio.h>
main()
{
int c;
while ((c = getchar()) != EOF){
putchar(c);
}
}
当处理长的表达式的时候,遇到算术符的优先级,加上括号是一个非常好的习惯。
习题1-6:
表达式getchar() != EOF永远为true,因为EOF本身无法用单个字符表示。EOF的值为-1,但是当你输入-1的时候,实际上输入了两个字符“-”,“1”。我们可以通过习题1-7知道EOF的准确值。
习题1-7:
#include <stdio.h>
main()
{
printf("%d\n", EOF);
}
显示-1.
1.5.2 字符计数
#include <stdio.h>
main()
{
long nc;
nc = 0;
while (getchar() != EOF)
{
++nc;
}
printf("%ld\n", nc);
}
程序输入输出:
我们可以用for循环简化(第一次看到这段代码的时候,我惊呆了)
#include <stdio.h>
main()
{
double nc;
for (nc = 0; getchar() != EOF; ++nc){
;
}
printf("%.0f\n", nc);
}
程序输入输出:
我第一次明白,原来分号(“;”)可以这样用。
1.5.3 行计数
#include <stdio.h>
main()
{
int c, nl;
nl = 0;
while ((c = getchar()) != EOF){
if ('\n' == c){
++nl;
}
}
printf("%d\n", nl);
}
程序输入输出:
当然,我们也可以用下面的代码完成同样的工作(不推荐):
#include <stdio.h>
main()
{
int c, nl;
nl = 0;
while ((c = getchar()) != EOF){
if (10 == c){
++nl;
}
}
printf("%d\n", nl);
}
1. 单引号中的字符表示一个整型值,该值等于此字符在机器字符集中对应的数值,我们称之为字符常量。但是,它只不过是小的整型数的另一种写法而已(比如‘\n’代表10),但是‘\n’的意义更加清楚,且与特定的字符集无关。
习题1-8:
#include <stdio.h>
main()
{
int c, ns, nt, nl;
ns = 0;
nt = 0;
nl = 0;
while ((c = getchar()) != EOF){
if (' ' == c){
ns++;
}
else if ('\t' == c){
nt++;
}
else if ('\n' == c){
nl++;
}
}
printf("空格符为%d\n制表符为%d\n换行符为%d\n", ns, nt, nl);
}
程序输入输出:
习题1-9:
#include <stdio.h>
main()
{
int c;
int bSpace = 0;
while ((c = getchar()) != EOF){
if (' ' == c){
bSpace = 1;
}
else{
if (bSpace){
putchar(' ');
bSpace = 0;
}
putchar(c);
}
}
}
习题1-10:
#include <stdio.h>
main()
{
int c;
while ((c = getchar()) != EOF){
if ('\t' == c){
printf("\\t");
}
else if ('\b' == c){
printf("\\b");
}
else if ('\\' == c){
printf("\\\\");
}
else{
putchar(c);
}
}
}
1.5.4 单词计数
#include <stdio.h>
#define IN 1 /*在单词内*/
#define OUT 0 /*在单词外*/
main()
{
int c, nl, nw, nc, state;
state = OUT;
nl = nw = nc = 0;
while ((c = getchar()) != EOF){
++nc;
if ('\n' == c){
++nl;
}
if ((' ' == c) || ('\n' == c) || ('\t' == c)){
state = OUT;
}
else if (state == OUT){
state = IN;
++nw;
}
}
printf ("%d %d %d\n", nl, nw, nc);
}
程序输入输出:
习题1-12:
#include <stdio.h>
main()
{
int c;
int nSpace = 0;
while ((c = getchar()) != EOF){
if ((' ' == c) || ('\t' == c)){
nSpace = 1;
}
else{
if (nSpace){
nSpace = 0;
putchar('\n');
}
putchar(c);
}
}
}
程序输入输出:
1.6 数组
#include <stdio.h>
main()
{
int c, i, nwhite, nother;
int ndigit[10];
nwhite = nother = 0;
for (i = 0; i < 10; i++){
ndigit[i] = 0;
}
while ((c = getchar()) != EOF){
if ((c >= '0') && (c <= '9')){
++ndigit[c - '0'];
}
else if ((' ' == c) || ('\n' == c) || ('\t' == c)){
++nwhite;
}
else{
++nother;
}
}
printf("digits =");
for (i = 0; i < 10; ++i){
printf(" %d", ndigit[i]);
}
printf(", white space = %d, other = %d", nwhite, nother);
}
只要明白,字符常量只是整型值的一种表达形式,那么这段代码将不难理解了。
习题1-13:
目前无法达到的一个高度是:通过EOF来显示所有的单词直方图结果,只要输入换行,则显示直方图的结果。
1-13-1: 水平直方图:
#include <stdio.h>
main()
{
int c;
int nCount = 0; //单词的长度
while ((c = getchar()) != EOF){
if ((' ' != c) && ('\t' != c) && ('\n' != c)){
putchar(c);
nCount++;
}
else{
if (nCount == 0) //处理连续的空格符,制表符和换行符
continue;
putchar(':');
while (--nCount >= 0){
putchar('*');
}
putchar('\n');
nCount = 0; //这里进行计数的纠正,否则nCount会变成-1,导致计数不准确
}
}
}
程序输入输出:
垂直直方图:
#include <stdio.h>
int main(void)
{
int c;
int nSpace = 0; //用于处理多空格,制表符情况
int nCount = 0; //用于处理:用*表示单词长度
int nl = 0; //用于判断显示是否换行
char nArray[10][5]; //用于存储单词--每个单词的长度限制为5,因为要在屏幕上显示出来(当然,如果你的屏幕足够大,一个单词长度可以为100)
char mArray[5][10]; //用于存储每个单词出现的星号
int i = 0;
int j = 0;
for ( i = 0; i < 10; i++ ){
for ( j = 0; j < 5; j++ ){
nArray[ i ][ j ] = ' ';
}
}
for ( i = 0; i < 5; i++ ){
for ( j = 0; j < 10; j++ ){
mArray[ i ][ j ] = ' ';
}
}
i = j = 0;
//显示单词和*的一个数组,比如二维数组的第一个元素是hello*****,后面加*号代表长度
while ( ( c = getchar() ) != EOF ){
if ( ( ' ' != c ) && ( '\t' != c ) && ( '\n' != c ) ){
nSpace = 0;
if ((j > 5) || (i > 9)){
break;
}
nArray[i][j++] = c;
}
else{
if (nSpace) //说明是多空格,所以忽略,继续输入
continue;
nSpace = 1;
nCount = j + 1;
while ( --nCount ){
mArray[ 5 - nCount ][ i ] = '*'; //这里的星号存放的顺序!!
}
i++;
j = 0;
}
}
for ( i = 0; i < 5; i++ ){
for ( j = 0; j < 10; j++ ){
printf("%c ", mArray[ i ][ j ] );
}
printf("\n");
}
for ( i = 0; i < 10; i++ ){
for ( j = 0; j < 5; j++ ){
printf("%c", nArray[ i ][ j ] );
}
printf(" ");
}
return 0;
}
程序输出:
这里主要是为了适应输出的客观性,所以就限制了只能输出10个单词,每个单词的长度要小于等于5.当然,水平直方图也可以参考这个代码,可以输出的更漂亮一些.
PS:顺便吐槽一下买的<C程序设计语言>的参考书,什么破答案.还是自己写的比较有保障一些.
习题1-14:
#include <stdio.h>
main()
{
int ndigits[52];
int c;
int i;
for (i = 0; i < 52; i++){
ndigits[i] = 0;
}
while ((c = getchar()) != EOF){
if (c >= 'a' && c <= 'z'){
++ndigits[c - 'a'];
}
else if (c >= 'A' && c <= 'Z'){
++ndigits[c - 'A' + 26];
}
}
for (c = 'a'; c <= 'z'; c++){
printf("%c:%d\n", c, ndigits[c - 'a']);
}
for (c = 'A'; c <= 'Z'; c++){
printf("%c:%d\n", c, ndigits[c - 'A' + 26]);
}
}
如果显示出垂直方向的直方图,我倒也不会写。
1.7 函数
我们通常把函数定义中圆括号列表中出现的变量称为形式参数,而把函数调用中与形式参数对应的值称为实际参数。
1.8 参数---传值调用
C语言中“通过值”传递,而在C++中,可以通过“引用”传递。
在C中,可以通过指针的概念达到类似“引用”传递的效果。
1.9 字符数组
读取并打印最长行:
#include <stdio.h>
#define MAXLINE 1000
int getline(char line[], int maxline);
void copy(char to[], char from[]);
main()
{
int len;
int max;
char line[MAXLINE];
char longest[MAXLINE];
max = 0;
while ((len = getline(line, MAXLINE)) > 0){
if (len > max){
max = len;
copy(longest, line);
}
}
if (max > 0){
printf("%s", longest);
}
return 0;
}
int getline(char s[], int lim){
int c,i;
for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i){
s[i] = c;
}
if (c == '\n'){
s[i] = c;
++i;
}
s[i] = '\0';
return i;
}
void copy(char to[], char from[]){
int i;
i = 0;
while ((to[i] = from[i]) != '\0'){
++i;
}
}
习题1-16:
通过链表可以达到无限制的输入:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct NODE{
int value;
struct NODE *next;
} Node;
void printNode( Node *node )
{
while ( node ){
printf("%c", node->value);
node = node->next;
}
printf("\n");
}
int main(void)
{
int count = 0; //当前行的长度
int maxLine = 0; //最大行的长度
int ch;
Node *node1 = NULL; //这里node1一定要初始化(PS:之前我经常忘记,因为用的是静态的节点,导致自动初始化)
Node *tempNode = NULL;
Node *resultNode = NULL;
while ( ( ch = getchar() ) != EOF ){
if ( ch != '\n' ){
count++;
tempNode = malloc( sizeof( Node ) );
tempNode->value = ch;
tempNode->next = node1;
node1 = tempNode;
}
else if( count > maxLine ){
Node *newNode;
Node *deleteNode;
maxLine = count;
count = 0;
while ( resultNode ){
deleteNode = resultNode;
resultNode = resultNode->next;
free( deleteNode ); //这里进行节点的删除的时候,一定要建立一个临时的变量进行存储节点,对临时的变量进行删除
}
while ( node1 ){
newNode = malloc( sizeof( Node ) );
newNode->value = node1->value;
newNode->next = resultNode;
resultNode = newNode;
node1 = node1->next;
}
}
}
printNode( resultNode );
return 0;
}
程序输出:
习题1-17:对习题1-16稍做修改即可,长度大于10的输出:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct NODE{
int value;
struct NODE *next;
} Node;
void printNode( Node *node )
{
printf("the line is : ");
while ( node ){
printf("%c", node->value);
node = node->next;
}
printf("\n");
}
int main(void)
{
int count = 0; //当前行的长度
int maxLine = 0; //最大行的长度
int ch;
Node *node1 = NULL; //这里node1一定要初始化(PS:之前我经常忘记,因为用的是静态的节点,导致自动初始化)
Node *tempNode = NULL;
Node *resultNode = NULL;
while ( ( ch = getchar() ) != EOF ){
if ( ch != '\n' ){
count++;
tempNode = malloc( sizeof( Node ) );
tempNode->value = ch;
tempNode->next = node1;
node1 = tempNode;
}
else {
Node *newNode;
Node *deleteNode;
while ( resultNode ){
deleteNode = resultNode;
resultNode = resultNode->next;
free( deleteNode ); //这里进行节点的删除的时候,一定要建立一个临时的变量进行存储节点,对临时的变量进行删除
}
while ( node1 ){
newNode = malloc( sizeof( Node ) );
newNode->value = node1->value;
newNode->next = resultNode;
resultNode = newNode;
node1 = node1->next;
}
if ( count > 10 ){
count = 0;
printNode( resultNode );
}
}
}
return 0;
}
程序输出:
1-18:
第二个hello world中包含了换行符和多余的空格:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLINE 128
int main(void)
{
int i = 0;
char arr[ MAXLINE ];
int lineLen = 0;
for ( i = 0; i < MAXLINE; i++ ){
arr[ i ] = '\0';
}
while ( NULL != fgets( arr, MAXLINE, stdin ) ){
for ( i = MAXLINE - 1; i >= 0; i-- ){
if ( ' ' == arr[ i ] || '\n' == arr[ i ] || '\t' == arr[ i ] ){
arr[ i ] = '\0';
}
else if ( arr[ i ] != '\0' ){
break;
}
}
for ( i = 0; i < MAXLINE; i++ ){
if ( '\0' == arr[ i ] ){
lineLen = i;
break;
}
putchar( arr[ i ] );
}
printf("\nthe line length is:%d\n", lineLen ); //这里不要用i来代表长度
for ( i = 0; i < MAXLINE; i++ ){ //要对arr进行删除操作
arr[ i ] = '\0';
}
}
return 0;
}
程序输出:
1-19:
#include <stdio.h>
void reverse( char *string )
{
char *temp = string;
while ( *temp ){
temp++;
}
temp--; //'\0'要省略
while ( temp > string ){
char ch = *temp;
*temp-- = *string;
*string++ = ch;
}
}
int main(void)
{
char str1[] = "hello";
char str2[] = "world";
reverse( str1 );
reverse( str2 );
printf("%s\n", str1 ); //str1本身就代表指针,不要输出*str1
printf("%s\n", str2 );
return 0;
}
程序输出:
1.10 外部变量与作用域
由于自动变量只在函数调用执行期间存在,因此,在函数的两次调用之间,自动变量不保留前次调用时的赋值,且在每次进入函数时都要显式为其赋值.如果自动变量没有赋值,则其中存放的是无效值.
外部变量必须定义在所有函数之外,且只能定义一次,定义后编译器程序将为它分配存储单元.在每个需要访问外部变量的函数中,必须声明相应的外部变量,此时说明其类型.声明时可以用extern语句显式声明,也可以通过上下文隐式声明.
#include <stdio.h>
#define MAXLINE 100 //允许的输入行的最大长度
int max; //到目前为止发现的最长行的长度
char line[ MAXLINE ]; //当前的输入行
char longest[ MAXLINE ];//用于保存最长的行
int getline( void );
void copy( void );
int main(void)
{
int len;
extern int max;
extern char longest[];
max = 0;
while ( ( len = getline() ) > 0 ){
if ( len > max ){
max = len;
copy();
}
}
if ( max > 0 ){
printf("%s", longest );
}
return 0;
}
int getline( void )
{
int c, i;
extern char line[];
for ( i = 0; i < MAXLINE - 1 && ( c = getchar() ) != EOF && c != '\n'; i++ ){
line[ i ] = c;
}
if ( '\n' == c ){
line[ i ] = c;
i++;
}
line[ i ] = '\0';
return i;
}
void copy( void )
{
int i;
extern char line[], longest[];
i = 0;
while ( ( longest[ i ] = line[ i ] ) != '\0' ){
i++;
}
}
如果程序包含在多个源文件中,而某个变量在file1文件中定义,在file2和file3文件中使用,那么在文件file2与file3中就需要使用extern声明来建立该变量与其定义之间的联系.
"定义"表示创建变量或分配存储单元,而"声明"指的是说明变量的性质,但并不分配存储单元.
1-20:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int ch;
int temp;
int isTab = 0;
while ( ( ch = getchar() ) != EOF ){
temp = ch;
if ( '\\' == ch && 0 == isTab ){
isTab = 1;
}
else{
if ( isTab ){
if ( 't' == ch ){
isTab = 0;
putchar( '\t' );
continue;
}
else if ( '\\' != ch ){
isTab = 0;
putchar( '\\' );
}
}
putchar( ch );
}
}
return 0;
}
程序输出:
但是答案似乎不是这样写,答案如下:
#include <stdio.h>
#define TABINC 8
int main(void)
{
int c, nb, pos;
nb = 0;
pos = 1;
while ( ( c = getchar() ) != EOF ){
if ( '\t' == c ){
nb = TABINC - ( pos - 1 ) % TABINC;
while ( nb > 0 ){
putchar( ' ' );
++pos;
--nb;
}
}
else if ( '\n' == c ){
putchar( c );
pos = 1;
}
else{
putchar( c );
++pos;
}
}
}
原来程序的含义是:将\t指定为8个(或者也可以4个)输出,看来我理解错误了.
1-21:题目没看懂其实.然后研究一下答案吧:
但是觉得这道程序貌似做无用功,把足够的空格符换成制表符输出,比如八个空格换成制表符,而一个制表符为4个空格,则只要输出4个空格就可以了.那为什么不直接计算有8个空格的时候,输出4个空格不就行了吗?
把答案粘贴出来吧,虽然我并不认可这种做法:
#include <stdio.h>
#define TABINC 8
int main(void)
{
int c, nb, nt, pos;
nb = 0;
nt = 0;
for ( pos = 1; ( c = getchar() ) != EOF; ++pos ){
if ( ' ' == c ){
if ( 0 != pos % TABINC ){
++nb;
}
else{
nb = 0;
++nt;
}
}
else{
for ( ; nt > 0; --nt ){
putchar( '\t' );
}
if ( '\t' == c ){
nb = 0;
}
else{
for ( ; nb > 0; --nb ){
putchar( ' ' );
}
}
putchar( c );
if ( '\n' == c ){
pos = 0;
}
else if ( '\t' == c ){
pos = pos + ( TABINC - ( pos - 1 ) % TABINC ) - 1;
}
}
}
}
1-22:
这是一种错误的思路,因为它严格按照书本上划分行了(我怀疑是书上翻译有问题的).第二段代码是自己个人觉得正确的代码.先把第一段代码copy上来:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLINE 128
void showMulLine( char *string, int index )
{
char *tempstr = string;
int len = strlen( string );
int tempLen;
int realIndex = index; //用于每次增加index
if ( len <= index ){ //当一行的长度小于要分割的长度时,直接输出
printf("%s\n", string );
return;
}
while ( index < len ){
tempLen = index;
while ( tempLen ){
if ( ' ' != string[ tempLen ] || '\t' != string[ tempLen ] ){ //略过空格和制表符
break;
}
tempLen--;
}
while ( string < &tempstr[ tempLen ] ){ //这里有个隐藏的BUG,之前是写成string < &string[ tempLen ],但是string在循环体内变了,所以这个变成了死循环!!!
putchar( *string );
string++;
}
printf("\n");
index += realIndex;
}
if ( index < len ){ //处理最后要分的行
while ( len ){
if ( ' ' != string[ len ] || '\t' != string[ len ] ){
break;
}
len--;
}
while ( string < &tempstr[ len ] ){
putchar( *string );
string++;
}
printf("\n");
}
}
int main(void)
{
char arr[ MAXLINE ];
while ( fgets( arr, MAXLINE, stdin ) != NULL ){
showMulLine( arr, 10 );
}
return 0;
}
程序输出:
正确的代码应该可以将world单词放在第二行,而不是强行分开:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLINE 128
void showMulLine( char *string, int index )
{
char *tempStr = string;
int pos = 0;
int tempPos = 0; //临时的索引,用于处理分行中空格后面的连续空格和空格后存在单词的情况
int tempIndex = 0; //临时的索引,用于处理分行中空格出现的情况
int isSpace = 0; //判断是否出现空格
int isMulSpace = 0; //判断是否出现多个空格
int isNewLine = 0; //用于删除一行开头的空格
while ( pos < index && '\n' != string[ pos ] ){
if ( pos == index - 1 && ' ' != string[ pos ] ){ //用于处理超过一个单词超过index长度的情况
putchar( string[ pos ] );
string += pos;
pos = 0;
continue;
}
if ( ' ' == string[ pos ] ){
isSpace = 1;
}
else{
tempPos = pos;
if ( !isSpace ){
putchar( string[ pos ] );
}
else{
isSpace = 0;
tempIndex = index;
//判断是否出现多个空格的情况
while ( tempPos < tempIndex ){
if ( ' ' == string[ tempIndex ] ){
isMulSpace = 1;
break;
}
tempIndex--;
}
if ( isMulSpace ){
putchar( ' ' ); //存在多个空格情况下,补齐第一个空格
isMulSpace = 0;
while ( tempPos < tempIndex ){
putchar( string[ tempPos ] );
tempPos++;
}
tempPos++; //存在多个空格情况下,将导致string的开头有个空格,故删除
}
putchar( '\n' );
string += tempPos;
pos = -1; //因为最终pos都要执行自增,所以赋值为-1,导致下次循环从0开始
}
}
pos++;
}
}
int main(void)
{
char arr[ MAXLINE ];
while ( fgets( arr, MAXLINE, stdin ) != NULL ){
showMulLine( arr, 10 );
}
return 0;
}
程序输出:
1.
2.
新的代码如下:
void showMulLine(char *line)
{
char arr[MAXLINE][MAXLINE] = {'\0'};
int i = 0;
int j = 0;
int isEnd = 0;
int size; //数组的个数
int len;
int index = 0;
//将输入的一行数据分割成以空白字符分割的字符串数组:hello world i love ,则数组中存储["hello ", "world ", "i ", "love "];
while (*line) {
if ((' ' == *line || '\t' == *line || '\n' == *line)) {
arr[i][j++] = *line;
line++;
isEnd =1;
continue;
}
if (' ' != *line && '\t' != *line && '\n' != *line) {
if (isEnd) {
j = 0;
i++;
arr[i][j++] = *line;
isEnd = 0;
} else {
arr[i][j++] = *line;
}
line++;
}
}
size = i;
len = 0;
index = 0;
//以LENGTH为长度进行分割操作
for (i = 0; i <= size; i++) {
len += strlen(arr[i]);
if (len < LENGTH) {
index++;
printf("%s", arr[i]);
}
else {
if (index == 0) {
printf("%s", arr[i]);
}
else {
i--;
}
printf("\n");
len = 0;
}
}
}
1-23:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXSIZE 128
#define LINENUM 20
int isDoubleSlash; //出现注释符'//'
int isSlashStar; //出现注释符/**/
void dealLine( char *line, char **mulLine, int index )
{
int len = strlen( line );
char *newLine = malloc( len * sizeof( char ));
char *temp = newLine;
while ( '\n' != *line ){ //备注:getline是以换行符/n结束,而不是以\0结束
if ( '/' == *line && '/' == *( line + 1 ) ){
isDoubleSlash = 1;
}
else if ( '/' == *line && '*' == *( line + 1 ) ){
isSlashStar = 1;
}
if ( isDoubleSlash ){ //出现'//',直接忽略后面的注释字符串
isDoubleSlash = 0;
*line = '\0';
break;
}
if ( isSlashStar && '*' == *line && '/' == *( line + 1 ) && '/' != *( line - 1 ) ){ //防止出现/*/的情况
isSlashStar = 0;
line += 2;
continue;
}
if ( !isSlashStar ){
*temp = *line;
temp++;
}
line++;
}
*temp = '\0';
mulLine[ index ] = newLine;
}
int main(void)
{
int ch;
char line[ MAXSIZE ];
char *mulLine[ LINENUM ];
int index = 0;
int i = 0;
int j = 0;
for ( i = 0; i < MAXSIZE; i++ ){
line[ i ] = '\0';
}
for ( i = 0; i < LINENUM; i++ ){
mulLine[ i ] = "";
}
while ( NULL != fgets( line, MAXSIZE, stdin ) ){
dealLine( line, mulLine, index );
index++;
}
printf("\nthe text is:\n");
for ( i = 0; i < LINENUM; i++ ){
if ( '\0' != mulLine[ i ][ 0 ] ){ //不要进行"" != mulLine[ i ]的判断
printf("%s\n", mulLine[ i ] );
}
}
return 0;
}
程序输出:
1-24:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXSIZE 128
#define LINENUM 20
int isDoubleSlash; //出现注释符'//'
int isSlashStar; //出现注释符/**/
//对注释进行处理
void dealLine( char *line, char **mulLine, int index )
{
int len = strlen( line );
char *newLine = malloc( len * sizeof( char ));
char *temp = newLine;
while ( '\n' != *line ){ //备注:getline是以换行符/n结束,而不是以\0结束
if ( '/' == *line && '/' == *( line + 1 ) ){
isDoubleSlash = 1;
}
else if ( '/' == *line && '*' == *( line + 1 ) ){
isSlashStar = 1;
}
if ( isDoubleSlash ){ //出现'//',直接忽略后面的注释字符串
isDoubleSlash = 0;
*line = '\0';
break;
}
if ( isSlashStar && '*' == *line && '/' == *( line + 1 ) && '/' != *( line - 1 ) ){ //防止出现/*/的情况
isSlashStar = 0;
line += 2;
continue;
}
if ( !isSlashStar ){
*temp = *line;
temp++;
}
line++;
}
*temp = '\0';
mulLine[ index ] = newLine;
}
//对方括号进行处理
int dealSquareBrackets( char *line )
{
int bracketNum = 0;
while ( '\0' != *line ){
if ( '[' == *line && 0 == bracketNum ){
bracketNum++;
}
else if ( ']' == *line && 0 != bracketNum ){
bracketNum--;
}
if ( bracketNum < 0 ){
return 1;
}
line++;
}
return bracketNum;
}
//对圆括号和花括号进行处理
int dealBrackets( char **mulLine )
{
char *temp;
int parenthesisNum = 0; //判断圆括号的次数
int braceNum = 0; //判断花括号的次数
int i = 0;
int countNum = 0;
int countParenthesisNum = 0; //计算左圆括号出现的位置
int countBraceNum = 0; //计算左花括号出现的位置
for ( i = 0; i < LINENUM; i++ ){
temp = mulLine[ i ];
while ( '\0' != *temp ){
countNum++;
if ( '(' == *temp ){
countParenthesisNum = countNum;
parenthesisNum++;
}
else if ( ')' == *temp ){
parenthesisNum--;
}
else if ( '{' == *temp ){
countBraceNum = countNum;
braceNum++;
}
else if ( '}' == *temp ){
braceNum--;
}
//右圆括号和右花括号不可出现在左圆括号和左花括号之前
if ( parenthesisNum < 0 || braceNum < 0 ){
return 1;
}
//圆括号中不可包含花括号
if ( 0 != parenthesisNum && 0 != braceNum && ( countParenthesisNum < countBraceNum ) ){
return 1;
}
//圆括号中不可出现分号';'
if ( 0 != parenthesisNum && ';' == *temp ){
return 1;
}
countNum = 0;
countParenthesisNum = 0;
countBraceNum = 0;
temp++;
}
}
//判断圆括号和花括号是否匹配
if ( 0 != parenthesisNum || 0 != braceNum ){
return 1;
}
return 0;
}
int main(void)
{
char line[ MAXSIZE ];
char *mulLine[ LINENUM ];
int index = 0;
int i = 0;
int j = 0;
int isOK = 0;
for ( i = 0; i < MAXSIZE; i++ ){
line[ i ] = '\0';
}
for ( i = 0; i < LINENUM; i++ ){
mulLine[ i ] = "";
}
//对注释进行处理
while ( NULL != fgets( line, MAXSIZE, stdin ) ){
dealLine( line, mulLine, index );
index++;
}
//对方括号进行处理
for ( i = 0; i < LINENUM; i++ ){
isOK = dealSquareBrackets( mulLine[ i ] );
if ( isOK ){
perror("1--brackets error:");
break;
}
}
//对圆括号和花括号进行处理
isOK = dealBrackets( mulLine );
if ( isOK ){
perror("2--brackets error:");
}
printf("\nthe text is:\n");
for ( i = 0; i < LINENUM; i++ ){
if ( '\0' != mulLine[ i ][ 0 ] ){ //不要进行"" != mulLine[ i ]的判断
printf("%s\n", mulLine[ i ] );
}
}
return 0;
}
程序输出: