C primer plus 复习题答案(上)

C primer plus 复习题答案

第一章 初识C语言

  1. 对编程而言,可移植性意味着什么

可移植性并不是指所写的程序不作修改就可以在任何计算机上运行,而是指当条件有变化时,程序无需作很多修改就可运行。

在软件工程中,可移植性,又译为移植性、可携性,是指使用高阶语言写成的软件,在不同环境下,是否具备可以被重复使用的性质。一般来说,软件是否具备可移植性的衡量标准,在于进行软件移植时,需要付出多少工时为代价。具备高可移植性的软件,在移植到不同系统平台时,并不需要做太多事情,因此能够减少软件开发及布署时的成本。为了使软件具备高度可移植性,程序员需要使应用程序界面抽象化以及模组化。

以低阶语言,例如汇编语言,写成的软件,一般来说,其可移植性都较低。

  1. 解释源代码文件,目标代码文件和可执行文件有什么区别?

源代码文件:程序语言编写的代码

目标代码:机器语言的代码组成

可执行代码:在计算机科学中指的是一种内容可以被电脑解释为程序的电脑文件

3.编程的7个主要的步骤是什么?

预编译又称为预处理, 是做些代码文本的替换工作。
在这里插入图片描述

  1. 编译器的任务是什么?

编译器将汇编或者高级计算机语言源程序作为输入,翻译为目标语言机器代码的等价程序

源代碼→預處理器 → 編譯器 → 目標代碼

  1. 连接器的任务是什么?

把目标文件和库文件链接成可执行文件

第二章 C语言概述

  1. C语言的基本模块是什么? 函数

  2. 什么是语法错误?
    写出一个英语例子和C语言例子 语法错误违反了组成语句或程序的规则 略

  3. 什么是语义错误?
    一个英语例子和C语言例子 语义错误是指含义错误

  4. Indiana Sloth编写了下面的程序,并征求你的意见。请帮助他评定。

#include stdio.hint main{void} /* 该程序打印一年有多少个周 */
(
    int s
    
s := 56;
printf(There ars s weeks in a year.);
return 0;

//下面修改

#include<stdio.h>
int main(void)
{
    int s;
    s = 56;
    printf("There are %d weeks in a year.",s);
    
    return 0;
}


5. 假设下面的4个例子都是完整程序中的一部分,它们都输出什么结果?

a. printf("Baa Baa Black Shep.");

printf("Have you any wool?\n");

b. printf("Begone!\nO creature of lard!\n");

c. printf("What?\nNo/nfish?\n");

d. int num;

num = 2;

printf(“%d + %d = %d”, num, num, num + num);


Baa Baa Black Shep.Have you any wool?

Begone

O creature of lard!

What

No/nfish?

2 + 2 = 4


  1. 在main、int、function、char、= 中,哪些是C语言关键字?

int、char

main 是函数名,function是函数的意思 , = 是运算符

  1. 如何以下面的格式输出变量words和lines的值?

There were 3020 words and 350 lines.

int words = 3020;

int lines = 350;

printf(“There were %d words and %d lines”, words, lines);

  1. 考虑下面的程序:
#include <stdio.h>
int main(void)
{
    int a, b;
    
​
a = 5;
b = 2;  /* 第7行 */
b = a;  /* 第8行 */
a = b;  /* 第9行 */
printf("%d %d\n", a, b);
return 0;}

代码分析:

第4行处声明了两个变量a和b

第6行,将值5赋给变量a,此时 a = 5,b由于未赋初值,暂不确定

第7行,将值2赋给变量b,此时a = 5, b = 2

第8行,将变量a的值赋给变量b,即将值5赋给变量b,此时 a = 5, b = 5

第9行,将变量b的值赋给变量a,即将值5赋给变量a,此时a = 5, b = 5

因此最终printf()函数输出 5 5。

VS运行结果如下:

在这里插入图片描述

  1. 考虑下面的程序:
#include <stdio.h>
int main(void)
{
    int x, y;
    
​
    x = 10;
    y = 5;      /* 第7行 */
    y = x + y;  /* 第8行 */
    x = x * y;  /* 第9行 */
    printf("%d %d\n", x, y);
    return 0;}

请问,在执行完第7,第8,第9行后,程序的状态分别是什么?

代码分析:

第4行处声明了两个变量x和y

第6行,将值10赋给变量x,此时 x = 10,y由于未赋初值,暂不确定

第7行,将值5赋给变量y,此时x = 10, y = 5

第8行,先计算表达式x + y的值,即 10 + 5 = 15,将值15赋值给y,此时x = 10, y = 15

第9行,先计算表达式x * y的值,即 15 * 10 = 150,将值150赋值给x,此时x = 150, y = 15

因此最终printf()函数输出 150 15。

在这里插入图片描述

第三章 数据和C

  1. 指出下面各种数据使用的合适的数据类型(有些可使用多种数据类型)

​ a. East Simpleton的人口 int

​ b.DVD影碟的价格 float

​ c.本章出现次数最多的字母 char

​ d.本次张出现次数自多的字母次数 short

  1. 在什么情况下要用long类型的变量代替int类型的变量
    在数据足够大超过了int类型的时候

  2. 使用那些可移植的数据类型可以获得32位有符号整数?选择的理由是什么?
    int32_t,可移植数据类型定义在inttypes.h头文件中,之所以有一个这样的头文件是,各个平台操作系统,对于基本类型关键字的存储范围不一,而有时候我们需要一种在各种平台下都要满足我们的需要固定范围的数据类型来存储,因此大家就定义了一个这样的头文件,这个头文件保证,它定义的数据类型别名,在各个系统下的存储范围(大小)一直,(ps:这里忽略此头文件中的最小长度类型,和最大长度类型)

  3. 指出下列常量的类型和含义(如果有的话):

     a. '\b'char类型常量(但是存储为int类型)
     b. 1066int类型常量
     c. 99.44double类型常量
     d. 0XAAunsigned int 类型常量,十六进制格式
     e. 2.0e30double类型常量
    

    5.请找出程序中的错误。

     include <stdio.h>
          main
          (
          float  g; h;			//float g,h;
          float  tax, rate;	
    
          g = e21;			   //e21定义不明	
          tax = rate*g;		//rate未定义,且可能会出现溢出的问题
          )
    
    
    
  4. 填写下表:

    常量类型转换说明(%转换字符)
    12int%d
    0X3unsigned%#X
    ’C’char%c
    2.34E+07double%e
    ’\ 040’char%c
    7.0double%f
    6Llong%ld
    6.0ffloat%f
    0x5.b6p12double%a
  5. 写出下列常量在声明中使用的数据类型和在printf()中对应的转换说明(假设int为16位):

    常量类型转换说明(%转换字符)
    12unsigned int%#o
    2.9e05Llong double%Le
    ’s’char%c
    100000int%d
    ’\ n’char%c
    20.0ffloat%f
    0x44unsigned int%x
    -40int%d
  6. 假设程序的开头有下列说明:

    int imate = 2;long shot = 53456;char grade = ‘A’;float log = 2.71828;
    //把下面的printf()语句中的转换字符补充完整:
    printf("The odds against the %d were %ld to 1.\n",imate,shot);
    printf("A score of %f is not an %c grade.\n", log, grade);
    
  7. 假设ch是char类型的变量。分别使用转义序列、十进制值、八进制字符常量和十六进制字符常量把回车字符赋给ch(假设使用ASCII编码值)。

    ch = '\r';
    ch = 13;
    ch = '\015';
    ch = '\xd';
    
  8. 修改下面的程序:

  void main(int) / this program is perfect/
  {
  cows, legs integer;
  printf("How many cow legs did you count?\n");
  scanf("%c",legs);
  cows = legs / 4;
  printf("That implies there are %f cows.\n",cows)
  }
答:
#include <stdio.h>
int main(void) /* this program is perfect */
{
	int cows, legs;
	

	printf("How many cow legs did you count?\n");
	scanf("%d", &legs);
	cows = legs / 4;
	printf("That implies there are %d cows.\n",cows);
	
	return 0;

}

11.指出下列转义序列的含义:

 a. \n     换行字符
 b. \ \     反斜杠字符
 c. \ "     双引号字符
 d. \ t     制表字符

第四章 字符串和格式化输入/输出

  1. 再次运行程序清单 4.1,但是在要求输入名时,请输入名和姓(根据英文书写习惯,名和姓中间有一个空格),看看会发生什么情况?为什么?

程序运行不正常,输入时输入姓名,如果有空格则后一个输入仍然会在缓存区只会输出缓冲区空格之前的内容

  1. 假设下列示例都是完整程序中的一部分,它们打印的结果分别是什么?

img

a. He sold the painting for $234.50.
b. Hi!
c.His Hamlet was funny without being vulgar.
	has 42 characters.
d .   Is 1.20e+003 the same as 1201.00?
  1. 在第2题的c中,要输出包含双引号的字符串Q,应如何修改?
printf("\"%s\"\nhas %d characters.\n", Q, strlen(Q));

  1. 找出下面程序中的错误
define B booboo 
define X 10 
main(int) 
{ 
    int age; 
    char name; 
    printf("Please enter your first name."); 
    scanf("%s", name); 
    printf("All right, %c, what's your age?\n", name); 
    scanf("%f", age); 
    xp = age + X; 
    printf("That's a %s! You must be at least %d.\n", B, xp);
    rerun 0; 
}
#define B "booboo"
#define X 10
#include<string.h>
#include<stdio.h>
int main(void)
{
	int age;
	char name[15];
	printf("Please enter your first name.");
	scanf("%s",name);
	printf("All right, %c, what's your age?\n",name);
	scanf("%d",&age);
	int xp = age + X;
	printf("That's a %s!You must be at least %d.\n",B,xp);
	
	
	return 0;
}
  1. 假设一个程序的开头是这样:

img
请构造一个使用BOOK,cost和percent的printf()语句,打印以下内容:

#define BOOK "War and Peace"
#include<stdio.h>

int main(void)
{
	float cost = 12.99;
	float percent = 80.0;
	
	printf("This copy of \"%s\" sell for $%2.2f.",BOOK,cost);
	
	printf("That is %2.0f%% of list .\n",percent);	
	
	
	return 0;
}
  1. 打印下列各项内容要分别使用什么转换说明?

img

a.%d
b.%4x
c.%10.3f
d.%12.2e
e.%-30s
  1. 打印下面各项内容要分别使用什么转换说明?

img

a.%15lu

b.%4x

c.%-12.2e

d.%+10.3f

e.%8.8s
  1. 打印下面各项内容要分别使用什么转换说明?

img

a.%6.4d

b.%*o

c.%2c

d.%+.2f

e.%-7.5s
  1. 分别写出读取下列各输入行的scanf()语句,并声明语句中用到变量和数组

img

a.

int a;

scanf("%d", &a);

b.

float b1, b2;

scanf("%f %f", &b1, &b2);

c.

char c[30];

scanf("%s", c);

d.

char d1[15];

int d2;

scanf("%s %d");

e.

int e;

scanf("%*s %d", &e);

  1. 什么是空白?

在C 中,这主要是指空格、制表符和(有时)换行符。 C++ 编译器通常会忽略空格,但有一些小例外。

  1. 下面的语句有什么问题?如何修正?

img

printf("The double type is %zd bytes..\n", sizeof(double));

z为修饰符,不是转换符
  1. 假设要在程序中用圆括号代替花括号,以下方法是否可行?

img

可以,但编译器无法识别哪些该换哪些不该换,所有的()都会被替换为{}


第五章 运算符、表达式和语句

  1. 假设所有变量的类型都是int,下列各项变量的值是多少:
    a.x = (2 + 3) * 6;
    b.x = (12 + 6)/23;
    c.y = x = (2 + 3)/4;
    d.y = 3 + 2
    (x = 7/2);
a.x = 30

b.x = 27

c.y = 1, x = 1

d.y = 9, x = 3
  1. 假设所有变量的类型都是int,下列各项变量的值是多少:
    a.x = (int)3.8 + 3.3;
    b.x = (2 + 3) * 10.5;
    c.x = 3 / 5 * 22.0;
    d.x = 22.0 * 3 / 5;
a.x = 6

b.x = 52

c.x = 0

d.x = 13
  1. 对下列各表达式求值:
    a.30.0 / 4.0 * 5.0;
    b.30.0 / (4.0 * 5.0);
    c.30 / 4 * 5;
    d.30 * 5 / 4;
    e.30 / 4.0 * 5;
    f.30 / 4 * 5.0;
a.37.5

b.1.5

c.35

d.37

e.37.5

f.35.0
  1. 请找出下面的程序中的错误
int main(void) 
{ 
    int i = 1, 
    float n; 
    printf("Watch out! Here come a bunch of fractions!\n"); 
    while (i < 30) 
        n = 1/i; 
    printf(" %f", n); 
    printf("That's all, folks!\n"); 
    return; 
}
#include <stdio.h>

int main(void)
{
    int i = 1;
    float n;
    printf("Watch out! Here come a bunch of fractions!\n");
    while (i < 30)
    {
        n = 1/i;
        printf(" %f", n);
        i++;
    }
    printf("That's all, folks!\n");
    return 0;
}
  1. 这是程序清单 5.9 的另一个版本。从表面上看,该程序只使用了一条 scanf()语句,比程序清单5.9简单。请找出不如原版之处
#include <stdio.h> 
#define S_TO_M 60 
int main(void) 
{ 
    int sec, min, left; 
    printf("This program converts seconds to minutes and "); 
    printf("seconds.\n"); 
    printf("Just enter the number of seconds.\n"); 
    printf("Enter 0 to end the program.\n"); 
    while (sec > 0) 
    { 
        scanf("%d", &sec); 
        min = sec/S_TO_M; 
        left = sec % S_TO_M; 
        printf("%d sec is %d min, %d sec. \n", sec, min, left); 
        printf("Next input?\n"); 
    } 
    printf("Bye!\n"); 
    return 0; 
}
//5.9
#include <stdio.h> 
#define SEC_PER_MIN 60      
int main(void) 
{ 
    int sec, min, left; 
    printf("Convert seconds to minutes and seconds!\n"); 
    printf("Enter the number of seconds (<=0 to quit):\n"); 
    scanf("%d", &sec);      
    while (sec > 0) 
    {
         min = sec / SEC_PER_MIN;  
        left = sec % SEC_PER_MIN;  
        printf("%d seconds is %d minutes, %d seconds.\n", sec, min, left); 
        printf("Enter next value (<=0 to quit):\n"); 
        scanf("%d", &sec); 
    } 
    printf("Done!\n"); 
    return 0; 
}

sec没有进行初始化,内存位置上存有未知的数据,当要结束输入的时候,仍然会输出一次0
6. 下面的程序将打印出什么内容?

#include <stdio.h> 
#define FORMAT "%s! C is cool!\n" 
int main(void) 
{ 
    int num = 10; 
    printf(FORMAT,FORMAT); 
    printf("%d\n", ++num); 
    printf("%d\n", num++); 
    printf("%d\n", num--); 
    printf("%d\n", num); 
    return 0; 
}

%s! C is cool!

! C is cool!

  1. 下面的程序将打印出什么内容?
#include <stdio.h> 
int main(void) 
{ 
    char c1, c2; 
    int diff; 
    float num; 
    c1 = 'S'; 
    c2 = 'O'; 
    diff = c1 - c2; 
    num = diff; 
    printf("%c%c%c:%d %3.2f\n", c1, c2, c1, diff, num); 
    return 0; 
}

SOS:4 4.00

  1. 下面的程序将打印出什么内容?
#include <stdio.h> 
#define TEN 10 
int main(void) 
{ 
    int n = 0; 
    while (n++ < TEN) 
    printf("%5d", n); 
    printf("\n"); 
    return 0; 
}

1 2 3 4 5 6 7 8 9 10

  1. 修改上一个程序,使其可以打印字母a~g。
#include <stdio.h> 
#define TEN 'g'
int main(void) 
{ 
    char n = 'a' - 1; 
    while (n++ < TEN) 
    printf("%5c", n); 
    printf("\n"); 
    return 0; 
}
  1. 假设下面是完整程序中的一部分,它们分别打印什么?
a. 
int x = 0; 
while (++x < 3) 
printf("%4d", x); 

b. 
int x = 100; 
while (x++ < 103) 
    printf("%4d\n",x); 
printf("%4d\n",x); 

c. 
char ch = 's'; 
while (ch < 'w') 
{ 
    printf("%c", ch); 
    ch++; 
} 
printf("%c\n",ch);
a.

   1   2

b.

 101

 102

 103

 104

c.

stuvw
  1. 下面的程序会打印出什么?
#define MESG "COMPUTER BYTES DOG" 
#include <stdio.h> 
int main(void) 
{ 
    int n = 0; 
    while ( n < 5 ) 
        printf("%s\n", MESG); 
    n++; 
    printf("That's all.\n"); 
    return 0;
}

重复打印 COMPUTER BYTES DOG 直到程序终止

  1. 分别编写一条语句,完成下列各任务(或者说,使其具有以下副作用):
    a.将变量x的值增加10
    b.将变量x的值增加1
    c.将a与b之和的两倍赋给c
    d.将a与b的两倍之和赋给c

x = x + 10

x = x + 1

c = 2 * (a + b)

c = a + 2 * b


  1. 分别编写一条语句,完成下列各任务:
    a.将变量x的值减少1
    b.将n除以k的余数赋给m
    c.q除以b减去a,并将结果赋给p
    d.a与b之和除以c与d的乘积,并将结果赋给x

x = x - 1

m = n % k

p = q / (b - a)//??歧义

x = (a + b) / (c * d)


第六章 C控制语句:循环

  1. 写出执行完下列各行后quack的值是多少。后5行中使用的是第1行quack的值。
        int quack = 2;
        quack += 5;
        quack *= 10;
        quack -= 6;
        quack /= 8;
        quack %= 3;

/*7 70 64 8 2*/

  1. 假设value是int类型,下面循环的输出是什么?
for ( value = 36; value > 0; value /= 2)
printf("%3d", value);

如果value是double类型,会出现什么问题?
36 18 9 4 2 1

如果value是double类型,当数据到0时候回你持续输出0.000

  1. 用代码表示以下测试条件:
a.大于5
b.scanf()读取一个double类型值且失败
c.X的值等于5

a>0;
scanf("%lf",&b)!=1;
x==5;
  1. 用代码表示以下测试条件:
a.scanf()成功读取一个整数
b.不等于
c.x大于或等于20

    
a. scanf("%d",&x)==1
b.x != 5
c.x >= 20
  1. 下面的程序有点问题,请找出问题所在。
#include <stdio.h>
int main(void)
{
    int i, j, list(10);
    for (i = 1, i <= 10, i++)
    {
        list[i] = 2 * i + 3;
        for (j = 1, j >= i, j++)
            printf(" %d", list[j]);
        printf("\n");
    }

    
    
   
#include<stdio.h>
int main(void)
{
	int i,j,list[10];
	for(i = 1;i <=10;i++)
	{
		list[i]= 2*i+3;
		for(j=1;j<=i;j++)
			printf("%d\t",list[j]);
		printf("\n");
	}
	return 0;
}
  1. 编写一个程序打印下面的图案,要求使用嵌套循环:
       /* 	$$$$$$$$
        	$$$$$$$$
        	$$$$$$$$
        	$$$$$$$$
        	
        */

            
            
#include<stdio.h>
int main(void)
{
	
	for(int i = 0;i<4;i++)
	{
			for(int j = 0;j<8;j++)
		{
			printf("$");
			
		}
		printf("\n");
	}
	return 0;
}
  1. 下面的程序各打印什么内容?
a.
#include <stdio.h>
int main(void)
{
    int i = 0;
    while (++i < 4)
        printf("Hi! ");
    do
        printf("Bye! ");
    while (i++ < 8);
    return 0;
}



/*Hi! Hi! Hi! Bye! Bye! Bye! Bye! Bye! */
b.
#include <stdio.h>
int main(void)
{
    int i;
    char ch;
    for (i = 0, ch = 'A'; i < 4; i++, ch += 2 * i)
        printf("%c", ch);
    return 0;
}
/*   ACGM   */
  1. 假设用户输入的是Go west ,young man!下列程序的输出是什么?(在ASCII码中,!紧跟在空格字符后面)
a.
#include <stdio.h>
int main(void)
{
    char ch;
    scanf("%c", &ch);
    while (ch != 'g')
    {
        printf("%c", ch);
        scanf("%c", &ch);
    }
    return 0;
}

//Go west ,youn


b.
#include <stdio.h>
int main(void)
{
    char ch;
    scanf("%c", &ch);
    while (ch != 'g')
    {
        printf("%c", ++ch);
        scanf("%c", &ch);
    }
    return 0;
}

//Hp!xftu-zpvo
c.
#include <stdio.h>
int main(void)
{
    char ch;
    do
    {
        scanf("%c", &ch);
        printf("%c", ch);
    } while (ch != 'g');
    return 0;
}

//Go west,young
d.
#include <stdio.h>
int main(void)
{
    char ch;
    scanf("%c", &ch);
    for (ch = '$'; ch != 'g'; scanf("%c", &ch))
        printf("%c", ch);
    return 0;
}
//$o,west,youn
  1. 下面的程序打印什么内容?
#include <stdio.h>
int main(void)
{
    int n, m;
    n = 30;
    while (++n <= 33)
        printf("%d|", n);
    n = 30;
    do
        printf("%d|", n);
    while (++n <= 33);
    printf("\n***\n");
    for (n = 1; n * n < 200; n += 4)
        printf("%d\n", n);
    printf("\n***\n");
    for (n = 2, m = 6; n < m; n *= 2, m += 2)
        printf("%d %d\n", n, m);
    printf("\n***\n");
    for (n = 5; n > 0; n--)
    {
        for (m = 0; m <= n; m++)
            printf("=");
        printf("\n");
    }
    return 0;
}

在这里插入图片描述

  1. 考虑下面的声明:
double mint[10];
a.数组名是什么?      						   mint	
b.该数组有多少个元素?						10
c.每个元素可以储存什么类型的值?				 double
d.下面的哪一个scanf()的用法正确?
i.scanf("%lf", mint[2]) 					x
ii.scanf("%lf", &mint[2])					v
iii.scanf("%lf", &mint)						x
  1. Noah先生喜欢以2计数,所以编写了下面的程序,创建了一个储存2、4、6、8等数字的数组。
    这个程序是否有错误之处?如果有,请指出。
#include <stdio.h>
#define SIZE 8
int main(void)
{
    int by_twos[SIZE];
    int index;
    for (index = 1; index <= SIZE; index++)
        by_twos[index] = 2 * index;
    for (index = 1; index <= SIZE; index++)
        printf("%d ", by_twos);
    printf("\n");
    return 0;
}

#include <stdio.h>
#define SIZE 8
int main(void)
{
    int by_twos[SIZE];
    int index;
    for (index = 0; index < SIZE; index++)
        by_twos[index] = 2 * (index + 1);
    for (index = 0; index < SIZE; index++)
        printf("%d ", by_twos[index]);
    printf("\n");
    return 0;
}

  1. 假设要编写一个返回long类型值的函数,函数定义中应包含什么?

返回long型別值的return語句

  1. 定义一个函数,接受一个int类型的参数,并以long类型返回参数的平方值。
long func(int i)
{
	return (long)n*n;
}
  1. 下面的程序打印什么内容?
#include <stdio.h>
int main(void)
{
    int k;
    for (k = 1, printf("%d: Hi!\n", k); printf("k = %d\n", k),k * k < 26; k += 2, printf("Now k is %d\n", k))
        printf("k is %d in the loop\n", k);
    return 0;
}

在这里插入图片描述

第七章 C控制语句:分支和跳转

  1. 判断下列表达式是true还是false。
a 100 > 3 && 'a'>'c'    F
b 100 > 3 || 'a'>'c'	T
c !(100>3)				F
  1. 根据下列描述的条件,分别构造一个表达式:
a  number等于或大于90,但是小于100
b  ch不是字符q或k
c  number在19之间(包括19),但不是5
d  number不在19之间
    
    
a. number >= 90 && number < 100
b. ch != 'q' && ch != 'k'
c. (number >= 1 && number <= 9) && number != 5
d. number < 1 || number > 9

  1. 下面的程序关系表达式过于复杂,而且还有些错误,请简化并改正。
#include <stdio.h>
int main(void)                  /* 1 */
{                        /* 2 */
	int weight, height; /* weight以磅为单位,height以英寸为单位 *//* 4 */
	scanf("%d , weight, height);          /* 5 */
	if (weight < 100 && height > 64)        /* 6 */

	if (height >= 72)             /* 7 */
		printf("You are very tall for your weight.\n");
	else if (height < 72 &&> 64)        /* 9 */
		printf("You are tall for your weight.\n");/* 10 */
	else if (weight > 300 && !(weight <= 300)  /* 11 */
		&& height < 48)            /* 12 */
	if (!(height >= 48))            /* 13 */
		printf(" You are quite short for your weight.\n");
	else                     /* 15 */
		printf("Your weight is ideal.\n");      /* 16 */
		/* 17 */
return 0;

}
          
          
          
          
#include <stdio.h>
int main(void)
{	
	int weight, height;
	
	scanf("%d %d", &weight, &height);  //修改
	if (weight < 100 && height > 64)
		if (height >= 72)
			printf("You are very tall for your weight. \n");
		else 		//修改
			printf("You are tall for your weight. \n");
	else if (weight > 300 && height < 48)	//修改
		printf(" Your are quite short for your weight. \n"); //修改
		else
			printf("Your weight is ideal. \n");

	return 0;
}

  1. 下列个表达的值是多少?
a.5 > 2
b.3 + 4 > 2 && 3 < 2
c.x >= y || y > x
d.d = 5 + ( 6 > 2 )
e.'X' > 'T' ? 10 : 5
f.x > y ? y > x : x > y
    
    
a. 1
b. 0
c. 1
d. 6
e. 10
f. 0
  1. 下面的程序将打印什么?
#include <stdio.h>
int main(void)
{
int num;
for (num = 1; num <= 11; num++)
{
if (num % 3 == 0)
putchar('$');
else
putchar('*');
putchar('#');
putchar('%');
}
putchar('\n');
return 0;
}


*#%*#%$#%*#%*#%$#%*#%*#%$#%*#%*#%


  1. 下面的程序将打印什么?
#include <stdio.h>
int main(void)
{
	int i = 0;
	while (i < 3) 
{
	switch (i++) 
	{
		case 0: printf("fat ");
		case 1: printf("hat ");
		case 2: printf("cat ");
		default: printf("Oh no!");
	}
	putchar('\n');
	}
	return 0;
}



fat hat cat Oh no !
hat cat Oh no !
cat Oh no !

  1. 下面的程序有哪些错误?
#include <stdio.h>
int main(void)
{
	char ch;
	int lc = 0; /* 统计小写字母
	int uc = 0; /* 统计大写字母
	int oc = 0; /* 统计其他字母
	while ((ch = getchar()) != '#')
	{
	if ('a' <= ch >= 'z')
		lc++;
	else if (!(ch < 'A') || !(ch > 'Z')
		uc++;
	oc++;
	}
	printf(%d lowercase, %d uppercase, %d other, lc, uc, oc);
	return 0;
}



#include  <stdio.h>
int main(void)
{	
	char ch;
	int lc = 0;
	int uc = 0;
	int oc = 0;
	
	while ((ch = getchar()) != '#') 
	{
		if (islower(ch))
			lc++;
		else if (isupper(ch))
			uc++;
		else
			oc++;
	}
	printf("%d lowercase, %d uppercase, %d other case", lc, uc, oc);

	return 0;
}


  1. 下面的程序将打印什么?
/* retire.c */
#include <stdio.h>
int main(void)
{
	int age = 20;
	while (age++ <= 65)
	{
		if ((age % 20) == 0) /* age是否能被20整除? */
	printf("You are %d.Here is a raise.\n", age);
	if (age = 65)
		printf("You are %d.Here is your gold watch.\n", age);
	}
	return 0;
}


Your are 65, Here is your gold watch.
Your are 65, Here is your gold watch.
Your are 65, Here is your gold watch.
Your are 65, Here is your gold watch.
Your are 65, Here is your gold watch.
Your are 65, Here is your gold watch.
Your are 65, Here is your gold watch.
.......

  1. 给定下面的输入时,以下程序将打印什么?
q
c
h
b
#include <stdio.h>
int main(void)
{
	char ch;
	while ((ch = getchar()) != '#')
	{
		if (ch == '\n')
			continue;
		printf("Step 1\n");
		if (ch == 'c')
		continue;
		else if (ch == 'b')	
			break;
		else if (ch == 'h')
		goto laststep;	
		printf("Step 2\n");
	laststep: printf("Step 3\n");
}
printf("Done\n");
return 0;
}

在这里插入图片描述

  1. 重写复习题9,但这次不能使用continue和goto语句。
/*
重写复习题9,但是不能使用 continue 和 goto 语句
*/
#include <stdio.h>
int main(void)
{	
	char ch;

	while ((ch = getchar()) != '#')
	{
		if (ch != '\n')
		{
			printf("Step 1 \n");
			if (ch != 'c')
			{
				if (ch == 'b')
					break;
				if ( ch == 'h')			//这几句还可以这样写
					printf("Step 3 \n");	// if (ch != 'h')
				else				//    printf("Step 2 \n");
				{				// printf("Step 3 \n");
					printf("Step 2 \n");	//
					printf("Step 3 \n");	//
				}				//
			}
		}
	}
	printf("Done \n");

	return 0;
}


第八章 字符输入/输出和输入验证

  1. putchar(getchar())是一个有效表达式,它实现什么功能?
    getchar(putchar())是否也是有效表达式?
是一个有效的的表达式,使程序读取下一个输入字符并打印出来、

getchar()的返回值是putchar()的参数。但getchar(putchar())是无效的表达式,因为getchar()不需要参数,而putchar()需要一个参数。
    
  1. 下面的语句分别完成什么任务?
a.putchar('H');
b.putchar('\007');
c.putchar('\n');
d.putchar('\b');



a. 打印字符 H

b. 如果系统使用ASDII,发出一声警报

c. 把光标移动到下一行

d. 把光标后退一格
  1. 假设有一个名为 count 的可执行程序,用于统计输入的字符数。设计一个使用 count 程序统计essay文件中字符数的命令行,并把统计结果保存在essayct文件中。
count < essay > essayct     or     count > essayct < essay


  1. 给定复习题3中的程序和文件,下面哪一条是有效的命令?
a.essayct  <essay
b.count essay
c.essay >count


都不是
  1. EOF是什么?
getchar() or scanf() 返回的特殊的值,表明函数检测到文件的结尾


  1. 对于给定的输出(ch是int类型,而且是缓冲输入),下面各程序段的输出分别是什么?
a.输入如下:
If you quit, I will.[enter]
程序段如下:
while ((ch = getchar()) != 'i')
putchar(ch);
b.输入如下:
Harhar[enter]
程序段如下:
while ((ch = getchar()) != '\n')
{
putchar(ch++);
putchar(++ch);
}




/*
a. If you qu

b.HJacrthjacrt

*/
  1. C如何处理不同计算机系统中的不同文件和换行约定?
C的标准I/O库会把不同的文件映射成统一的流来处理


  1. 在使用缓冲输入的系统中,把数值和字符混合输入会遇到什么潜在的问题?
数字会跳过空格和换行符,但是字符输入不会:

输入数字的时候,空格和换行符还会留在缓存区,输入字符的时候会读取。

【在输入数字之后要处理空格和换行符】

第九章 函数

  1. 实际参数和形式参数的区别是什么?
形式参数:
被定义在被调用函数中的变量

实际参数:

出现在函数调用中的值,该值被附给形式参数
  1. 根据下面各函数的描述,分别编写它们的ANSI C函数头。注意,只需写出函数头,不用写函数体。
a.donut()接受一个int类型的参数,打印若干(参数指定数目)个0
b.gear()接受两个int类型的参数,返回int类型的值
c.guess()不接受参数,返回一个int类型的值
d.stuff_it()接受一个double类型的值和double类型变量的地址,把第1个
值储存在指定位置

a. void donut(int);

b. int gear(int, int);

c. int guess();

d. void stuff_it(double, double*)

  1. 根据下面各函数的描述,分别编写它们的ANSI C函数头。注意,只需写出函数头,不用写函数体。
a.n_to_char()接受一个int类型的参数,返回一个char类型的值
b.digit()接受一个double类型的参数和一个int类型的参数,返回一个int类
型的值
c.which()接受两个可储存double类型变量的地址,返回一个double类型
的地址
d.random()不接受参数,返回一个int类型的值

a. char n_to_char(int);

b. int digit(double, int);

c. double* which(double*, double*);

d. int random();
  1. 设计一个函数,返回两整数之和。
int add(int a,int b)
{
    return a + b;
}
  1. 如果把复习题4改成返回两个double类型的值之和,应如何修改函数?
double add(double a, double b)
{
    return a + b;
}
  1. 设计一个名为alter()的函数,接受两个int类型的变量x和y,把它们的值分别改成两个变量之和以及两变量之差。
void alter(int *a, int *b)
{ 
    int temp = *a + *b;
    *b = *a - *b;
    *a = temp;
    return;
}
  1. 下面的函数定义是否正确?
void salami(num)
{
int num, count;
for (count = 1; count <= num; num++)
printf(" O salami mio!\n");
}
void salami(int num) 
{ 
    int count; 
    for (count = 1; count <= num; count++) 
        printf(" O salami mio!\n"); 
}
  1. 编写一个函数,返回3个整数参数中的最大值。
int max(int a,int b,int c)
{
    return a > b?(a>c?a:c):(b>c?b:c); 
}
  1. 给定下面的输出:
Please choose one of the following:

1) copy files         2) move files

3) remove files       4) quit
   Enter the number of your choice:
   a.编写一个函数,显示一份有4个选项的菜单,提示用户进行选择(输
   出如上所示)。
   b.编写一个函数,接受两个int类型的参数分别表示上限和下限。该函数
   从用户的输入中读取整数。如果整数超出规定上下限,函数再次打印菜单
   (使用a部分的函数)提示用户输入,然后获取一个新值。如果用户输入的
   整数在规定范围内,该函数则把该整数返回主调函数。如果用户输入一个非
   整数字符,该函数应返回4。

   c.使用本题a和b部分的函数编写一个最小型的程序。最小型的意思是,
   该程序不需要实现菜单中各选项的功能,只需显示这些选项并获取有效的响
   应即可。
#include <stdio.h>
#include <stdlib.h>

void menu()
{
    printf("Please choose one of the following: \n");
    printf("1) copy files          2) move files \n");
    printf("3) remove files        4) quit\n");
    printf("Enter the number of your choice:");
}

int ul(int u, int l)
{
    int num;
    while(scanf("%d", &num) == 1)
    {
        if(num >= l && num <= u)
        {
            return num;
        }
        else
        {
            menu();
        }
    }
    return 4;
}

int main(void)
{
    int u, l;
    scanf("%d %d", &l, &u);
    int x = ul(u, l);
    printf("\nXXXX%d\n", x);
    return 0;
}

第十章 数组和指针

  1. 下面的程序将打印什么内容?
#include <stdio.h>
int main(void){ 
	int
	ref[] = { 8, 4, 0, 2 };
	int *ptr;
	int index;
	for (index = 0, ptr = ref; index < 4; index++, ptr++)
		printf("%d %d\n", ref[index], *ptr);
	return 0;
} 
输出结果为:
8 8
4 4
0 0
2 2
  1. 在复习题1中, ref有多少个元素?
 4
  1. 在复习题1中, ref的地址是什么? ref + 1是什么意思? ++ref指向什
    么?
ref 的地址为数组首元素8的地址,即 &ref[0]
ref + 1 指向下一个元素4的的地址,即 &ref[1]
++ref 指向下一个元素的的地址,即 &ref[1]
++ref不是一个有效的表达式,因为ref是一个常量,不是变量!!!
  1. *在下面的代码中, * ptr和 (ptr + 2)的值分别是什么?
a.
int *ptr;
int torf[2][2] = {12, 14, 16};
ptr = torf[0];


*ptr = 12   * (ptr + 2) = 16

b.
int * ptr;
int fort[2][2] = { {12}, {14,16} };
ptr = fort[0];


*ptr = 12   * (ptr + 2) = 14

  1. 在下面的代码中, *ptr和 (ptr + 1)的值分别是什么?
a.
int (*ptr)[2];   //ptr指向一个内含两个int类型数值的数组
int torf[2][2] = {12, 14, 16};
ptr = torf;

** ptr = 12   ** (ptr + 1) = 16

b.
int (*ptr)[2];
int fort[2][2] = { {12}, {14,16} };
ptr = fort;

** ptr = 12   ** (ptr + 1) = 14

  1. 假设有下面的声明:
 int grid[30][100];
 a.1种写法表示grid[22][56]地址
  *( * ( grid + 22 ) + 56 )
 b.2种写法表示grid[22][0]地址
  *( * ( grid + 22 ) + 0 )
 c.3种写法表示grid[0][0] 地址
  &grid[0][0]或grid[0]或(int *)grid
  1. 正确声明以下各变量:
a.digits是一个内含10int类型值的数组
 int digits[10];
b.rates是一个内含6float类型值的数组
 float rates[6];
c.mat是一个内含3个元素的数组, 每个元素都是内含5个整数的数组
 int mat [3] [5];
d.psa是一个内含20个元素的数组, 每个元素都是指向int的指针
 int *psa[20];
e.pstr是一个指向数组的指针, 该数组内含20char类型的值
 char (*pstr)[20];
a.声明一个内含6int类型值的数组, 并初始化各元素为12481632
 int a[6] = {1, 2, 4, 8, 16, 32};
b.用数组表示法表示a声明的数组的第3个元素(其值为4)
 a[2]
c.假设编译器支持C99/C11标准, 声明一个内含100int类型值的数组,
并初始化最后一个元素为-1, 其他元素不考虑。
 int b[100] = { [99] = -1 };
d.假设编译器支持C99/C11标准, 声明一个内含100int类型值的数组,
并初始化下标为51011123的元素为101, 其他元素不考虑
 int c[100] = { [3] = 101, [5] = 101, [10] = 101, 101, 101 };
  1. 内含10个元素的数组下标范围是什么?
 [ 0, 9 ]
  1. 假设有下面的声明:
float rootbeer[10], things[10][5], *pf, value = 2.2;
int i = 3;
判断以下各项是否有效:
a.rootbeer[2] = value;   对
b.scanf("%f", &rootbeer );  对   无效
c.rootbeer = value;    错
d.printf("%f", rootbeer);  错
e.things[4][4] = rootbeer[3]; 对
f.things[5] = rootbeer;   错,不能用数组赋值
g.pf = value;       错
h.pf = rootbeer;       对
  1. 声明一个800×600的int类型数组
int a[800] [600];
  1. 下面声明了3个数组:
double trots[20];
short clops[10][30];
long shots[5][10][15];
a.分别以传统方式和以变长数组为参数的方式编写处理trots数组的void
函数原型和函数调用
b.分别以传统方式和以变长数组为参数的方式编写处理clops数组的void
函数原型和函数调用
传统方式:
void sum(short clops[ ][30], int n);
sum(trots)
变长数组:
void sum(int a, int b, short clops[a][b]);
sum(10, 20, clops)

c.分别以传统方式和以变长数组为参数的方式编写处理shots数组的void
函数原型和函数调用
    
    
    
    a.
void func(double []);
void func(int, double [*]);

/*
题目说的是调用- -自闭
void func(double a[]){}
void func(int a, double b[a]){}
*/
func(trots);
func(20, trots);

b.
void func(short [][30]);
void func(int, int, short [*][*]);

/*
void func(short a[][30]){}
void func(int a, int b, short c[a][b]){}
*/
func(clops);
func(10, 30, clops);

c.
void func(long [][10][15]);
void func(int, int, int, long[*][*][*]);

/*
void func(long a[][10][15]){}
void func(int a, int b, int c, long d[a][b][c]){}
*/
func(shots);
func(5, 10, 15, shots);

  1. 下面有两个函数原型:
void show(const double ar[], int n);    // n是数组元素的个数
void show2(const double ar2[][3],int n);  // n是二维数组的行数
a.编写一个函数调用, 把一个内含8392的复合字面量传递给
show()函数。
    show((int[4]) {8,3,9,2},4);
    

b.编写一个函数调用, 把一个23列的复合字面量(839作为第1
行, 541作为第2行) 传递给show2()函数。

    show2((int [][3]){{8,3,9},{5,4,1}},2);

第十一章 字符串和字符串函数

  1. 下面字符串的声明有什么问题?
int main(void)
{
	char name[] = {'F', 'e', 's', 's'};      		//少了'0'
	
}

//如果希望得到一个字符串,初始化列表中应该包括'\0',当然也可以用另一种语法自动添加空字符:

char name[] = "Fess";
  1. 下面的程序会打印什么?
#include <stdio.h>
int main(void)
{
	char note[] = "See you at the snack bar.";
	char * ptr;

	ptr = note;
	puts(ptr);			//See you at the sanck bar.
	puts(++ptr);		//ee you at the sanck bar.
	note[7] = '\0';		
	puts(note);			//See you
	puts(++ptr);		//e you
	
	return 0;

}
See you at the snack bar.
ee you at the snack bar.
See you
e you
  1. 下面 程序会打印什么?
#include <stdio.h>
#include <string.h>
int main(void)
{
	char food[] = "Yummy";
	char * ptr;		

	ptr = food + strlen(food);	
	while (--ptr >= food)		
		puts(ptr);				
		
	return 0;

}

y
my
mmy
ummy
Yummy
  1. 下面 程序会打印什么?
#include <stdio.h>
#include <string.h>
int main(void)
{
	char goldwyn[40] = "art of it all ";
	char samuel[40] = "I read p";
	const char * quote = "the way through.";

	strcat(goldwyn, quote);
	strcat(samuel, goldwyn);
	puts(samuel);

	return 0;
}


I read part of it all the way through .

  1. 下面的练习设计字符串、循环、指针和递增指针。首先定义了下面的函数:
#include <stdio.h>
char *pr(char *str)
{
	char *pc;

	pc = str;
	while (*pc)
		putchar(*pc++);
	do {
			putchar(*--pc);
		} while (pc - str);
	
	return (pc);

}

考虑下面的函数调用:x = pr(“Ho Ho Ho!”);
a.

Ho Ho Ho!!oH oH oH

b.

指向char类型的指针   char *

c.

'H’的地址

d.

相当于 *- -pc),- -*pc)的区别,前者是先使用指针解引用后递减指针的值,后者是先解引用指针的值后递减指针指向的地址的值的大小(例如H变为G)

e.

会打印Ho Ho Ho!没了

f.

答:第一个入口测试条件while使得当指针指向字符串末尾的空字符时,停止循环体
第二个出口测试条件do while中的条件(pc - str)使得当pc指向字符串首元素时停止循环体

g.

答:第一个while循环不会打印任何东西。第二个while循环:指针指向空字符前面的位置,将该字节解释成一个字符并打印,重复,永远都不会满足条件pc-str=0(pc==str),所以这个 过程会一直持续下去
运行结果如图:后两行是CodeBlocks下运行自带的

h.

答:必须再主调函数中定义一个指向字符串的指针如:char * pt;并且要给pr()传递一个指向char类型的指针如: pt = pr("String");(Ps:字符常量是指针)


6.假设有如下声明
char sign = ' ′ ; s i g n 占用多少字节的内存 ? ′ '; sign占用多少字节的内存?' ;sign占用多少字节的内存'占用多少字节的内存?"$"占用多少字节的内存?

sign 占一个字节
'$'字符常量储存为int型,所以$占用2个或4个自己
 "$"字符串使用两个字节,一个字节存储$,另一个字节存储'\0'   
  1. 下面的程序会打印出什么?
#include <stdio.h>
#include <string.h>
#define M1 "How are ya, sweetie? "
char M2[40] = "Beat the clock.";
char * M3 = "chat";
int main(void)
{
    char words[80];
    printf(M1);			//这行也打印How are ya, sweetie?
    puts(M1);			//How are ya, sweetie?
    puts(M2);			//Beat the clock.
    puts(M2 + 1);		//eat the clock.
    strcpy(words,M2);	//
    strcat(words, " Win a toy.");
    puts(words);		//Beat the clock Win a toy.
    words[4] = '\0';	
    puts(words);		//Beat
    while (*M3)			
        puts(M3++);		//chat  换行 hat 换行 at 换行 at 换行 t
    puts(--M3);			//t 
    puts(--M3);			//at
    M3 = M1;				
    puts(M3);				//How are ya, sweetie?
    

    return 0;

}


/*
How are ya, sweetie?How are ya, sweetie?
Beat the clock.
eat the clock.
Beat the clock. Win a toy.
Beat
chat
hat
at
t
t
at
How are ya, sweetie?
*/
  1. 下面的程序会打印出什么?
#include <stdio.h>
int main(void)
{
    char str1[] = "gawsie"; // plump and cheerful
    char str2[] = "bletonism";
    char *ps;
    int i = 0;
    

    for (ps = str1; *ps != '\0'; ps++)
    {
        if ( *ps == 'a' || *ps == 'e')	//如果*ps等于字符a或e打印a或e,
            putchar(*ps);
        else							//否则打印该字符ASCII码减一对应的字符
        	(*ps)--;
        putchar(*ps);
    }
    putchar('\n');
    while (str2[i] != '\0' )		//遍历直到末尾
    {
        printf("%c", i % 3 ? str2[i] : '*');//下标是3的倍数打印*字符,否则打印本身*
        ++i;
    }
    
    return 0;

}
faavrhee
*le*on*sm
  1. 本章定义的s_gets()函数,用指针表示法代替数组表示法便可减少一个变量i,请改写该函数。
char * s_gets(char * st, int n)
{
	char * ret_val;
	int i = 0;

	ret_val = fgets(st, n, stdin);
	if (ret_val)
	{
		while (st[i] != '\n' && st[i] != '\0')
			i++;
		if (st[i] == '\n')
			st[i] = '\0';
		else
			while (getchar() != '\n')
				continues;
	}
	
	return ret_val;

}
  1. strlen()函数接受一个指向字符串的指针作为参数,并返回该字符串的长度。请编写一个这样的函数。
int strlen(const char * st)
{
	int ct = 0;
	

	while (*st++)
		ct++;
	
	return ct;	

}
  1. 本章定义的s_gets()函数,可以使用strchr()函数代替其中while循环来查找换行符。请改写该函数。
#include <stdio.h>
#include <string.h>
char * s_gets(char * st, int n)
{
	char * ret_val;
    char * find;

	ret_val = fgets(st, n, stdin);
	if (ret_val)
	{
	    find = strchr(st, '\n');		//返回'\n'所在的地址
	    if (find)
	        *find = '\0';
		else
			while (getchar() != '\n')
				continue;
	}
	
	return ret_val;

}
  1. 设计一个函数,接受一个指向字符串的指针,返回指向该字符串第1个空字符的指针,或如果未找到空格字符,则返回空指针。
char * strch(char * st)
{	
	while (*st != ' ' && *st != '\0')
		st++;
	if (*st == ' ')
		return st;
	else return null;
}

下面是第二种方案,可以防止函数修改字符串,但是允许使用返回值改变字符串。表达式(char *)string被称为“通过强制类型转换取消const”

#include <stdio.h>	// 提供NULL的定义
char * strblk(const char * st)
{
	while (*st != ' ' &7 *st != '\0')
		st++;
	if (*st == '\0')
		return NULL;
	else
		return (char *)st;
}
  1. 重写程序清单11.21,使用ctype.h头文件中的函数,以便无论用户选择大写还是小写,该程序都能正确答案。
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define SIZE 40
#define ANSWER "GRANT"
char * s_gets(char * st, int n);
void ToUpper(char * st);
int main(void)
{
	char try[SIZE];

	puts("Who is buried in Grant's tomb?");
	s_gets(try, SIZE);
	
	while (strcmp(try, ANSWER) != 0)
	{
		puts("No, that's wrong. Try again.");
		s_gets(try, SIZE);
	}
	puts("That's right!");

}
char * s_gets(char * st, int n)
{
	char * ret_val;
	int i = 0;

	ret_val = fgets(st, n, stdin);
	ToUpper(ret_val);
	if (ret_val)
	{
		while (ret_val[i] != '\0' && ret_val[i] != '\n')
			i++;
		if (ret_val[i] == '\n')
			ret_val[i] = '\0';
		else
			while (getchar() != '\n')
				continue;
	}
	
	return ret_val;

}

void ToUpper(char * st)
{
		while (*st)
		{
			*st = toupper(*st);
			st++;
		}
}


  • 61
    点赞
  • 184
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不好,商鞅要跑

谢谢咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值