易错点

  • 程序填空题:已知程序的功能也要将整个程序的每一个语句看完 (通常有坑)
  • 求平均值,近似值(小数点)的题目,注意int类型相除赋值给float型的错误
  • 填条件时
    • i 的值是为1还是为0,i 是小于还是小于等于
    • i++ 还是 i– ,i- -通常是逆序操作
    • 循环次数是几次?
    • == 还是 != ?
  • %f输出时,小数不足6位添0 → 89.500000
  • 问输出结果的时候,注意有没有换行符,制表符等。
  • 调用两个参数的函数时,注意写入实参的顺序有没有坑。fun(&y, &x)
  • for循环,j=0,1,2,3 里面条件为if(j%2) 满足真的j值有0和2.(不要忽略了0)
  • 特别注意问输出结果:printf的变量是int还是double型的。
    double w = int(a+b) 那么w仍然是作为double型输出的。
  • int t[ 3 ] [2] 则&t[ 3 ] [ 2 ]不能表达其数组元素的地址,因为越界了!
  • C语言中的按位运算:
    • & 相同为1不同为0
    • | 全为0才为0
    • ^ 相同为0不同为1
    • ~ 取反 与!功能类似
      关于负数的补码:eg.-2 → 2为0010,从右到左遇到第一个1的后面取反:1110
  • 递归函数中的printf,注意按值传递的递归函数返回上一层原变量的值依旧。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stido.h>
int b;
void fun(int a);
int main()
{
fun(0);
return 0;
}
void fun(int a)
{
a=a+2;
b=a+b;
printf("%d,%d\n",a,b);
if(a<4)
fun(a);
printf("%d,%d\n",a,b);
}

输出结果:
2 2
4 6
4 6
2 6 //返回上层递归函数 a的值并不会传回来,依旧是2!

知识点

  • continue不能用于switch语句,因为switch语句不是循环语句,是分支选择结构,break可以用于循环语句和switch语句。
  • switch后面的“表达式”,可以是int、char和枚举型中的一种,不能是float型变量;case后面必须是“常量表达式”,表达式中不能包含变量
  • enum在c语言中是关键字 ,c语言对大小写比较敏感,所以ENUM是一个标识符,但不是关键字。
  • 有如下说明int a[10]={1,2,3,4,5,6,7,8,9,10}, * p=a;
    • 本题主要考查指针变量对数组元素的引用。在本题中,首先一个一维数组a,并对其进行初始化操作,然后定义了一个同类型的指针变量p,使其指向数组a的首地址。
    • 通过指针引用数组元素主要分如下两种情况。
      引用数组a首元素的常用等价方式有:
      ① 获取首元素地址:a,p;
      ② 访问首地址的值:a[0],p[0], * a, * p。
      引用
      数组第i个元素
      (从0开始计数)的常用等价方式有:
      ① 获取i元素地址:a+i,&a[i],p+i,&p[i];
      ② 访问i运算的值:* (a+i),a[i],* (p+i),p[i]。
  • 初始化整型数组时,未赋值元素自动初始化为0。定义数组时,仅指定了数组长度而未初始化,整型自动复制为0,字符型’\0’,指针型NULL
  • char单个字符和char数组(即字符串)类型的指针赋值输出的区别:
1
2
3
4
5
6
7
8
9
10
char *p="hello"; p指向了静态字符串常量的地址
char p[]="hello"; -> char p[5];
strcpy(p, "Hello world");
char *p;
p="hello";

char a[5]="hello"; char a='c';
char *p; char *p;
p=a; p=&a;
printf("%s",p); printf("%c",*p); //printf("%s",p);单个字符两者都可注意区别
  • 数组名是指向首元素地址,仅仅是代表一个地址而不是指针。不能与指针等价,不能进行自加预算或是当成指针赋值。
1
2
3
4
5
6
7
8
char s[10];
s="right";× 数组名不能这样直接赋值。
s[10]="right"
char s[10]="hello"; √ 会自动在末尾添'\0'
char s[10]={"hello"}; √

等价于 char s[10]={'h','e','l','l','o','\0'};
不等价于 char s[10]={'h','e','l','l','o'};
  • EOF 为一个宏名,不能作为用户标识符。EOF宏的值为 -1,EOF 宏表示读文件到了结尾这一状态,返回值为-1。这种状态可以用 feof(fp) 来检测,如果遇到文件结束,函数feof(fp)的值为非零值,否则为0。
  • 数组指针可以用p[ i ]来表示数组元素。
1
2
3
4
5
6
7
8
9
int a[3]={1,2,3};
int *p=a;
printf("%d",p[1]);
printf("%d",*(p+1));
printf("%d",a[1]); printf("%d",*(a+1));

p++;
printf("%d",*p);√
a++; × 数组名不能自加,仅仅是能看a[0]的指针。
  • printf(strlen(“1234567\0\0”)) 输出为7,因为strlen()函数不会计算空字符’\0’。
  • printf(“%d”,(int)strlen(“a\n"\x4e”));输出为4。\x4e是16进制ASCII码,表示一个字符N,类似还有\x41是16进制ASCII码,表示一个字符A。
  • 已有定义”char ch=6; int i=6,j;” 执行”j=ch | | i++”以后,i的值为6。**& & 和| | 从左向右判断到能出结果的时候就不再继续往下判断了。**
  • 函数insertsubstr的功能是:将字符串s2插入到字符串s1中指定位置c字符前。如果字符串s1中没有c字符,插入失败,函数返回0,如果有c字符,插入成功,返回1。
1
2
3
4
5
6
7
8
9
10
11
12
13
int insertsubstr(char *s1, char *s2, char c)
{
char *p1;
p1=strchr【(s1, c)】;
if(p1==NULL)
return 0;
else
{
strcat(s2, p1)】;
strcpy(p1, s2);
return 1;
}
}
  • 执行语句:for(i=1; i++<10)后,循环控制变量 i 的值是11。先比较,再自加。
  • 关于返回指针值的函数
    • 函数可以返回自动变量、静态局部变量的值,但是不能返回自动变量的地址。可以返回静态局部变量的地址。
  • 设有C语句序列:struct T{ int num, int age} t, * p; p=& t ;则对结构体变量 t 的成员age引用
    • 正确表达: t.age p -> age ( * p).age
    • 错误表达: * p.age
  • 结构体变量的存储空间是连续的,但其中可能会因对齐方式而导致实际结构体所占空间大于结构体变量所有成员所占空间之和。联合体的存储空间是占用最大存储空间成员所需的存储空间。
  • 32/64位系统,int类型变量都是占4个字节。书上:Turbo2.0为int分配2个字节,Visual C++为int分配4字节。
  • 在C语言中,进行关系运算时,逻辑值“真”用数字1表示,逻辑值“假”是用数字0表示。判别时,任何非0数字都能够被系统解释为“逻辑真”
  • 已知定义 int (* p)( ); p可以指向函数的入口地址。
  • 写出下面程序执行后的结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <stdio.h>
void main()
{
int i,j;
for(int i=0; i<5; i++)
{
for(int j=1;j<10;j++)
if(j=5)
break;
if(i<2)
continue;
if(i>2)
break;
printf("j=%d,",j);
}
print("i=%d\n",i);
}
内层for循环和if语句没有用括号,要注意breakcontinue到底是作用的哪个for
输出结果为:j=5,i=3
#include <stdio.h>
#include <string.h>
void fun(char *s, int n);
void main(){
char str[] = "ABCDEFG";
fun(str,strlen(str);
puts(str);
}
void fun(char *s, int n)
{
char t, *s1, *s2;
s1=s; s2=s+n-1;
while(s1<s2)
{
t=*s1++;
*s1=*s2;
*s2--=t;
}
}
注意s1,s2是指向的同一个数组的指针。和指向两个相同数组的指针区别。
输出为:AGFEFGA

#include <stdio.h>
struct A{
int x;
int *y;
}a[4],*p;
int main(){
int n=10,i;
for(i=0;i<4;i++)
{
a[i].x=n;
a[i].y=&a[i].x;
n+=5;
}
p=a;
p++;
printf("%d,%d\n",*(p++)->y,*(++p)->y);
return 0;
}
注意指针的自加结合解引用。*p++ 等同于*(p++),自增p但返回p自增之前的值。
输出为1525.
  • char ch=’a’; //97
    int k=12;
    printf(“%x,%o,”,ch,ch,k);
    printf(“k=%%d\n”,k);
    输出为:61,141,k = % d
    • printf函数按照后面的参数对应的顺序逐个输出,而不理会参数的个数,如果前面的输出多,如printf(“%x,%o,%d,%d,%d”,ch,ch,k);则多出的部分输出随机数;如果后面的多,如printf(“%x,%o,”,ch,ch,k);则,按顺序输出,多余的被忽略
    • printf中的%表示格式化输出,即按照**%后面设定的格式输出,所以,每两个%就会忽略前面的那个,而取后面的部分,因此 % % d将会输出%d**,而%d不是一个格式,不会输出十进制数字,而是在忽略前一个%后,原样输出,即输出k = % d。
  • 设A为存放短整型的一维数组,如果A的首地址为P,那么A中的第i个元素的地址为P+(i-1) * 2。 (地址而不是指针,需要乘以short int的字节数2
  • 设有说明double( * p1)[N], * p2[N];
    • 标识符p1是一个指向由N个double型元素组成的一维数组
    • 标识符p2是具有N个指针的一维指针数组,每个元素都只能指向double型量
  • char * func(int x, int y);它是对函数func的原型声明
  • 对二维数组a进行正确初始化:
    • 全部赋初值时,可以不指定第一维,但必须指定第二维
    • 赋初值可以全部写在一个花括号里,也可以按行赋值(每一行写在一个花括号里)。按行赋值时没赋值的元素默认为0(int型)。
  • 设有如下定义:char * a[2]={“abcd, “ABCD”};
    • a数组的两个元素中各自存放了字符’a’和’A’的地址。√
    • a数组的两个元素分别存放的是含有4个字符的一维字符数组的首地址。×
      因为a数组是指向字符型的指针数组,而不是指向一维字符数组的。
  • float f=3.14159727;
    printf(“%f,%5.4f,%3.3f”, f, f, f);
    则程序输出结果为:3.141593, 3,1416, 3.142 会四舍五入!区别于整型相除
  • 建立一个名为myflie的文件并输入…. fp=fopen(“myfile”, “w”)新建myfile文件并赋予写入相应内容的权限
  • 浮点数不精确,在作为判断条件时候不能用==,其他的可以,包括>=等。
  • x和y为double型,则表达式x=2, y=x+3/2的值是3.000000。
  • int i=1, j=2, k=3;
    if(i++==1&&++j==3 || k++==3) \k++==3不会被执行,上一步已经判断完值
    printf(“%d %d %d\n”,i, j, k); 输出为2 3 3
  • 能正确进行字符串赋值的是:
    • char s[5]={‘A’, ‘B’, ‘C’, ‘D’,’E’}; × 没有终止符‘\0’只是字符数组不是字符串
    • char * S; S=”ABCDE”; √
  • 在文件包含预处理语句的使用形式中,当#include后面的文件名用(双引号)括时,寻找被包含文件的方式是先在源程序所在的目录搜索,如没找到,再按系统设定的标准方式搜索。

编程题

  • a.txt b.txt 相同字符作为新的字符串存入c.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char arr[256]={'\0'}, a[256], b[256];
//*arr *a *b不可以 只是指针 不能代表字符串数组的 注意区别
//arrc初始化'\0' 是因为可能一个相同的也没有
int n=0;
FILE *fpa, *fpb, *fpc;
if((fpa=fopen("a.txt","r"))==NULL)
{
printf("cannt \n");
exit(0);
}
if((fpb=fopen("b.txt","r"))==NULL)
{
printf("cannt \n");
exit(0);
}
if((fpc=fopen("c.txt","w"))==NULL)
{
printf("cannt \n");
exit(0);
}
fgets(a,256,fpa);
fgets(b,256,fpb);
char *p;
for(int i=0;*(a+i)!='\0';i++)
{
for(int j=0;*(b+j)!='\0';j++)
{
if(*(a+i)==*(b+j))
{
p=strchr(arr,*(a+i));
if(p==NULL){
arr[n]=*(a+i);
n++;
arr[n]='\0';
}
}
}
}
fputs(arr,fpc);
fclose(fpa);
fclose(fpb);
fclose(fpc);
return 0;
}
  • 读取a.txt中的文本行为字符串,并将每一行的数字字符转换成一个实数,将每一行的这些实数的和写入a.txt的尾部。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <stdio.h>
int main(){
double extraNumber(char *s);
char s[255];
double sum,num;
FILE *fp;
if((fp=fopen("a.txt","r+"))==NULL) //不知道为什么vscode运行 a+ 不行
{
printf("cannot open the file");
return 0;
}
while(fgets(s,255,fp)!=NULL) // while(!feof(fp)){
{ // fgets(s,255,fp);
num = extraNumber(s);
sum += num;
}
fprintf(fp,"%f",sum);
fclose(fp);
return 0;
}

double extraNumber(char *s)
{
double num=0;
for(int i=0;*(s+i)!='\0';i++)
{
if((*(s+i)>='0') && (*(s+i)<='9'))
num = num*10 + (double)(*(s+i)-'0');
}
return num;
}

a.txt before after
abc1c23de abc1c23de
sa1da2sd3a sa1da2sd3a246.000000
  • 从键盘上反复输入字符串(直到输入空字符串为止),将字符串中的所有小写字母转换成对应大写字母,其他字符保持不变,然后后写入文本文件a.txt中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#include <string.h>
int main(){
FILE *p;
char s[255];
if((p=fopen("a.txt","w"))==NULL)
{
printf("cannot open the file\n");
return 0;
}
while(strlen(gets(s)))
{
for(int i=0;s[i];i++)
if(s[i]>='a' && s[i] <= 'z')
s[i] -=32;
fprintf(p,"%s\n",s); //fputs(s,p); fputc('\n',f);
}
fclose(p);
return 0;
}