1.有以下程序,输出的结果为

1
2
3
4
5
6
7
8
9
10
#include<string.h>
#include<stdio.h>
main()
{
char p[20]={'a','b','c','d'},q[]="abc",r[]="abcde";
strcpy(p+stlen(q),r);//(p+strlen(q)):意思是多出3(strlen(q))个字符来储存p的前三个字符,strcpy本来是全部覆盖,然后现在从第四个开始覆盖
//此时数组p内的内容变为{a,b,c,a,b,c,d,e,\0,\0,\0,\0,\0,\0,\0,\0,\0,\0,\0,\0}
strcat(p,q);//数组p内容变为{a,b,c,a,b,c,d,e,a,b,c,\0,\0,\0,\0,\0,\0,\0,\0,\0}
printf("%d %d\n",sizeof(p),strlen(p));
}
1
2
3
4
5
6
7
//strcpy会把/0也复制到新的数组中
//strlen会在看到(第一个)/0时停止计数
设有
static char str[ ]="Beijing";
则执行
printf("%d\n", strlen(strcpy(str,"China")));
后的输出结果为 //A
注意点:
  • sizeof:计算数组(变量)所占空间大小,注意,\0也是一个字符-----操作符

  • strlen:求字符串长度,到\0就停止,并且\0不算字符串内容,strlen也不把\0计算到字符串长度中

    例子:

    • char arr1[]="abc";

      char arr2[]={'a','b','c'};

      printf("%d",sizeof(arr1));//4

      printf("%d",sizeof(arr2));//3

      printf("%d",strlen(arr1));//3

      printf("%d",strlen(arr2));//15(随机数),因为找不到\0,字符串后才有\0

  • 注意:sizeof求所占空间大小算的是比特位,如果是char类型就×1相当于其中字符个数

  • int arr[]={1,2,3,4} 如果是int类型的就要×4

    • sizeof(arr)=4×4=16(bit位)
数组长度的计算方法: size=sizeof(arr)/sizeof(arr[0])
1
2
已有定义:char a[ ]= ″xyz″,b[ ]={ ′x′, ′y′, ′z′};
//所以a的长度为4,因为a后面默认是有\0的;b的长度为3

2.下列程序输出结果是

1
2
3
4
5
6
7
8
#include<stdio.h>
void main()
{
char w[][10]={"ABCD","EFGH","IJKL","MNOP"};
int k;
for(k=1;k<3;k++)
printf("%s\n",&w[k][k]);
}

解答:FGHKL,%s指输出字符串,所以从起始位置到此行结束的所有字符都将被输出

3.下列程序输出结果是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1.#include<string.h>
void main()
{
char str[30];
strcpy(&str[0],"NEXT");
strcpy(&str[1]),"OR");
strcpy(&str[2],"TICE");
printf("%s\n",str);
}

2.#include<stdio.h>
void main()
{
char w[][10]={"ABCD","EFGH","IJKL","MNOP"};
int k;
for(k=1;k<3;k++)
printf("%s\n",&w[k][k]);
}

1.解答:NOTICE

注意:数组名通常情况下代表首元素地址(2种情况例外)

  • sizeof(数组名):此时数组名表示整个数组,sizeof(数组名)计算的是整个数组的大小
  • &数组名:代表整个数组,&数组名,取出的是整个数组的地址
  • strcpy是全部覆盖

2.解答:FGHKL

注意:因为输出的是%s的字符串类型,所以会输出头后所有的,一连串输出

4.以下程序输出结果是

1
2
3
4
5
6
#include<stdio.h>
void main()
{
int a=30;
printf("%d",(a/3>0)?a/10:a%s);
}
  • 三目运算符的运算顺序是从右到左,当a/3是真的就输出a/10;当a/3为假那么输出a%3,因为a/3是判断语句不是赋值语句,所以a/3=10,但是a还是30

5.if(a=5)是允许的

6.以下语句的输出结果是:

1
2
3
char s[10];
s="abcd";
printf("%s\n",s);

注意:C语言中无字符串变量,不能直接用赋值语句对一个数组整体赋值

7.野指针(写代码时极易出现的错误)

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
//野指针1
int main()
{
//未初始化的指针变量(非法访问)
int* p;//局部变量不初始化,里面默认放的是一个随机值
*p = 20;//相当于把20放在了内存中随机的一块地址
return 0;
}//当编写程序的时候不知道当时要给指针赋予什么样的值那么 int* p=NULL; (void *)0,把0强制转换成void *xing
//野指针2:指针越界访问
int main()
{
int a[10] = { 0 };
int i = 0;
int* p = a;
for (i = 0; i <= 12; i++)
{
*p = i;(*p++=i)
p++;
}
return 0;
}
//返回局部变量或临时变量的地址
int* text()
{
int a = 10;//局部变量的存在,只在所在大括号内
return &a;
}
int main()
{
int* p = text();
printf("%d\n", *p);
return 0;
}

8. 以下程序输出结果是:

1
2
3
4
5
6
7
main()
{
int a[]={2,4,6,8},*p=a,i;
for(i=0;i<4;i++)
a[i]=*p++;
printf("%d\n",a[2]);
}

注意:p++运算等价于 (p++),先运算地址增值再解引用操作,但由于是p++,所以是先赋值后+1

9.以下函数的类型是

1
2
3
4
fff(float x)
{
printf("%d\n",x*x);
}

注意:只有int类型可以省略在函数名前,是否返回值是取决于项目目的,void类型基本不返回返回值,其他类型也可能没有返回值。

10.下列程序的输出结果是

1
2
3
4
5
6
7
8
9
10
fun(int a,int b,int c)
{
c=a*b;
}
main()
{
int c;
fun(2,3,c);
printf("%d\n",c);
}

注意:变量c进入func函数后并没有输出,也没有返回值,并且处理的数据只能在该函数体范围内有效,所以无法确定输出结果

11.以下不能正确定义二维数组的选项是

1
2
3
4
int a[2][2]={{1},{2}};   //对 
int a[][2]={1,2,3,4}; //对
int a[2][2]={{1},{2,3}}; //对
int a[2][]={{1,2},{3,4}};//错
  • 注意:在定义二维数组时,如果对所有元素赋初值,其第1维的长度可以省略
  • 二维数组初始化也可以只对每一行或若干个行的前若干元素赋初值
  • 在二维数组定义中不能省略第二维的长度

12.以下程序的输出结果为

1
2
3
4
5
6
#include"stdio.h"
void main()
{
int a=30;
printf("%d",(aa/3>0)?a/10:a%3);
}

13.指针在C语言中的规定

注意:C语言规定,允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//1
#define N_VALUES 5
float values[N_VALUES];
float *vp;
for(vp=&values[0];vp<&values[N_VALUES];)
{
*vp++=0;
}
//2
#define N_VALUES 5
float values[N_VALUES];
float *vp;
for(vp=&values[N_VALUES-1];vp>=&values[0];vp--)
{
*vp=0;
}
//相比于第二种写法更建议第一种写法

14.指针与数组

  • 注意:一般情况下数组名指的就是首元素地址,但是有两个例外:
    • 1.&arr- &数组名- 数组名不是首元素的地址-数组名表示的是整个数组-&数组名,取出的是整个数组的地址
    • sizeof(arr)-sizeof(数组名)-数组名表示的是整个数组-sizeof(数组名)计算的是整个数组的大小
1
2
3
4
5
6
7
int arr[10]={0};
printf("%p\n",arr);//1.首元素的地址00EFF8E0
printf("%p\n",arr+1);//00EFF8E4
printf("%p\n",&arr[0]);//2.首元素地址00EFF8E0
printf("%p\n",&arr[0]+1);//00EFF8E4
printf("%p\n",&arr);//全部元素地址,虽然打印出来和1,2相同为00EFF8E0,但意义不同
printf("%p\n",&arr+1);//00EFF908(与00EFF8E0相差40,因为跳过一整个数组地址)

15.以下函数有几个实参

1
exece((v1,v2),(v3,v4),v5,v6)

注意:(v1,v2)和(v3,v4)是两个逗号表达式,结果分别为v2,v4所以一共有4个实参

16.栈,堆

  • 栈上保存局部变量和函数形参
  • 堆上保存全局变量

17.下列代码打印出的结果为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<stdio.h>
int main()
{
int arr[]={1,2,3,4,5}
short *p=(short*)arr;
int i=0;
for(i=0;i<4;i++)
{
*(p+i)=0;
}
for(i=0;i<5;i++)
{
printf("%d",arr[i]);
}
return 0;
}

注意:将数组arr的首元素地址强制转换为short类型(short类型为2个字节),所以(*p+i)赋值给了数组元素中1,2的这8个字节(先赋值元素1的前两个字节,后赋值1的后两个字节,元素2同理)

1
2
3
4
5
6
7
8
9
#include<stdio.h>
int main()
{
int a=0×11223344;
char *pc=(char*)&a;
*pc=0;
printf("%x\n",a);
return 0;
}

注意:

  • 内存块的存放方法:倒着存放44 33 22 11一共4个字节(44,33,22,11分别占位一个字节),但是打印时要复原地址顺序

  • char*只能访问一个字节

18.下列代码打印出来的结果是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include<stdio.h>
int i;//全局变量未初始化默认初始化为0
int main()
{
i--;
if(i>sizeof(i))//sizeof-计算变量/类型所占内存的大小,恒>0(不可能返回负数),为无符号数,一个整数和无符号数进行运算(比较大小,或者加减乘除)的时候,会把这个整数转换为无符号数,再进行计算。
{
printf(">\n");
}
else
{
printf("<\n");
}
return 0;
}

注意:-1:10000000000000000000000000000001 源码

​ 11111111111111111111111111111110 反码

​ 11111111111111111111111111111111 补码

19.正确的执行结果是

1
2
3
int i=0;
while(i<=2);
printf("%d",i++);

注意:while();这是一个没有执行语句的while循环:;的位置

20.以下程序的输出结果是

1
2
3
4
5
# include <stdio.h>
main()
{ int i=010 , j = 10; //010是八进制数,十进制数为8
printf("%d,%d\n",+ +i , j - -); } //9,10
//八进制的整数都是以0开头,十六进制的整数以0x开头,在C语言中只有十进制数有负数
1
2
char c='\72';
//其中、72代表一个字符,72是八进制数,代表ASCII码值的字符":"

21.以下程序的输出结果是

1
2
3
4
5
main()
{ int a=4,b=5,c=0,d;
d=!a&&!b||!c;
printf("%d\n",d);
} //1
  • 常用的运算符优先级(由高到低)

    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
    !     ++     --

    × / %(要求运算时必须为整形)

    + -

    << >> 左移和右移运算符

    > < ≥ ≤

    == !=

    &&

    ||

    ?:

    += -= *=

    =

    ,


1
设有语句int  a=3;则执行了语句a+=a-=a*a;后,变量a的值是 -12//+=和-=的运算按顺序从右向左

22.下列程序的运行结果是

1
2
3
4
5
6
7
8
9
void fun(int *a, int *b)
{ int *k;
k=a; a=b; b=k;
}
main()
{ int a=3, b=6, *x=&a, *y=&b;
fun(x,y);
printf("%d %d", a, b);
}
  • 结果是: 3 6

  • 形参都是值传递,但是这个值是指针的话,是可以改变指针指向内容的值,即实参的值。但是要弄清两个概念:指针和指针指向的数据。这个例子中形参的值是实参的地址,并不是实参的值,所以形参的值的改变只是指针的改变,即指向数据的地址改变,并不是指针指向数据的改变。

23.执行下面程序中的输出语句后,变量 a 的值为(逗号表达式)

1
2
3
# include <stdio.h>
main ( )
{ int a ; printf ( “ %d \n ”, ( a = 3 * 5 , a * 4 , a + 5 ) ) ; } //a=15
  • x=表达式1,表达式2,表达式3;

因为逗号表达式是优先级最低的表达式,赋值表达式的优先级高,所以会把表达式1的值直接赋值给x

  • x=(表达式1,表达式2,表达式3);

括号里的先执行,逗号表达式是左结合性,所以会从左往右依次执行,最后再把表达式3的值赋给x

注意:

上面的题是求变量a的值,如果上面的例题变为,求逗号表达式a=2×6,a×3,a+5的值

逗号表达式的结果是整个表达式执行完最后的一个值

可以把这个式子看成x=(a=2×6,a×3,a+5) a=2×6=12,这时表达式的式子为12;a×3并不是一个赋值语句,表达式的值还是12;最后x=(a+5)=12+5=17;该表达式为17
应用:
1
func((exp1,exp2),(exp3,exp4,exp5))  //2个实参

上述函数调用语句中有几个实参? 2个

24.以下程序的输出结果是

1
2
3
# include <stdio.h>
main()
{ printf("%d\n",NULL); } //0

25.C语言中的定义问题

1
2
3
4
5
6
7
8
9
10
11
12
1.C语言的基本单位位是函数
2.在宏定义 #define PI 3.14159中,用宏名PI代替是字符串
3.C语言规定,程序中各函数之间既允许直接递归调用也允许间接递归调用
4.指针的算数运算(p为指针变量,px为另一个指针变量)(两个基本类型相同的指针变量不能进行加法运算)
+ p+n 指针向地址大的方向移动n给数据
- p-n 指针向地址小的方向移动n个数据
++ p++或++p 指针向地址大的方向移动一个数据
-- p--或--p 指针向地址小的方向移动一个数据
- p-px 注意:两个指针相隔元素的个数
5.C语言程序的三种基本结构是顺序结构、选择结构和循环结构
6.在C语言的条件判断语句中可用任意的表达式来决定分支的流程
7.在C语言中数字029是一个非法数

26.或逻辑短路和与逻辑短路

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
设 a=5, b=6, c=7, d=8, m=2, n=2, 执行
(m=a>b)&&(n=c>d)
后n的值为 //BBB
//短路问题的结论”或(||)“逻辑前面为1,”与(&&)”逻辑前面为0就会短路
1.或逻辑短路
int main()
{
int a=5,b=6,c=7,d=8,m=2,n=2;
(m=a<b)||(n=c>d);
printf("%d\t%d",m,n);
}
//的结果为1,2,因为a<b,m=1,这个或逻辑就被“短路”掉了,后面的语句就没有执行,所以n还是等于原来的2.||只要有一个为1,结果就为1.因此短路,并且不计算(n=c>d)
2.与逻辑短路
int main()
{
int a=5,b=6,c=7,d=8,m=2,n=2;
(m=a>b)&&(n=c>d);
printf("%d\t%d",m,n);
}
//结果为0,2,因为a>b为0,m=0,整个“与”逻辑就判断为”假“所以后面的“n=c>d”就被忽略掉了,所以n还是等于原来的2
//另外:标准的逻辑与(|)与逻辑或(&),无论第一个表达式为真还是假都计算第二个表达式

27.隐式转换问题

1
若有定义:int a=8,b=5,C;,执行语句C=a/b+0.4;后,c的值为//B
注意:

在使用赋值运算符的时候,当赋值号右边数据类型和左边数据类型不相同时,系统将自动将赋值号右边数据转换成与左边数据相同的数据类型,然后再赋值(这里不是四舍五入,而是取整操作)

28.固定位宽问题

1
2
3
4
5
6
以下程序段的输出结果是__C___。
int a=1234
printf("%2d\n",a); //1234
printf("%2d",1); //输出_1(_代表空格)
printf("%2d",102); //输出102
printf("%2d",12.23); //输出12(强制类型转换,即取整数部分)

29.不同类型变量进行运算规则

系统有默认的转化规则,就是从精度低的转化为精度高的,避免计算时精度的丢失

具体转化规则如下:

char--->short--->int--->unsigned(无符号数)--->long--->unsigned long--->float--->double

1
设有整型变量a,单精度型变量f,双精度型变量x,则表达式a+’b’+x*f值的类型为  

30.%和/的运算

1
2
语句if(3/4>1/2) a=1; else a=0;执行该语句后,a的值是   //0
//在C语言中3/4 (1/2)等于0;3%4 (1%2)等于3 (1)

31.合法实性常数的判断规则

实型常量又称实数或浮点数,在C语言中可以用两种形式来表示一个实型常量1.小数形式2.指数形式

在C语言中,以“e”或E后跟一个整数来代表以十为底的幂数。其一般形式是aEn,其中a为十进制数,n为十进制整数

注意:

C语言规定字母e或E之前必须要有数字,且e或E后面的数只能是整数

以下选项中合法的实型常数是
1
2
3
4
5
以下选项中合法的实型常数是 //3
1. 5E2.0
2. E-3
3. 2E0
4. 1.3E

32.