在C语言中,double、long、unsigned、int、char类型数据所占字节数
整型(int):4个字节(-2^31~2^31-1)
unsigned int (0~2^32-1)
短整型(short):2个字节
长整型(long):4个字节
字符型(char):1个字节
单精度浮点型(float):4个字节(6~7位有效位)
双精度浮点型(double):8个字节(15~16位有效位)
一、概述
1.C语言的标识符是怎样组成的?
合法的标识符必须由英文字母或下划线开头,是字母、数字河下划线的序列,不能跨行书写,自定义的标识符不能与关键字同名。
2.构成c语言源程序的基本单位是(函数)
3.在c程序中,main函数的位置(可以任意)
4.一个c程序执行是从(main函数开始,直到main函数结束)
5.c语言的源程序通常以(.c)作为其拓展名
一个 C 源程序从编辑到编译、链接直至运行完毕,分别生成的文件及后缀情况如下:.c 、 .obj、 .exe
#include<stdio.h>
int main()
{
int x;
scanf("%d",&x);
//没有类似的二进制输出样式
printf("%o\n",x);//8进制
printf("%x\n",x);//16进制
return 0;
}
二、基本数据类型
1.优先级(*,/,%)>(+,-)
2.典型运算
1)-5 % 3
-5 = 3 * q + r 得q=-1,r=-2 即-5%3=-2
2)5 % -3
5 = -3 * q + r 得q=-1,r=2 即-5%3=2
3)a*=a+3
a=a*(a+3)
4)int x=2,y=2 则 (!x||y--)
首先!x的值为0,x不为0,取非后为0
随后是逻辑或,因为逻辑或前是0,所以要看后边
因为y--是后置运算符,所以在计算逻辑或是y=1,即最终表达式的值为1
3.运算优先级
B(3)
4.
void main()
{
int c1=97,c2=98;
printf("%c,%c\n",c1,c2);//c1=a,c2=b
printf("%d,%d\n",c1,c2);//c1=97,c2=98
}
void main()
{
char c1='a',c2='b',c3='c',c4='\101',c5='\116';
printf("a%cb%c\tc%c\tabc\n",c1,c2,c3);//aabb(下一制表位)cc(下一制表位)abc
printf("\t\b%c%c",c4,c5);//(下一制表位)(退格)AN
}
利用条件表达式完成下边的命题:学习成绩>=90分的同学用'A'表示,60~89分的同学用'B‘表示,60分以下的同学用’C'表示:grade>=90 ? 'A' : (grade>=60 ? 'B' : 'C');
5
D ffff
- 在 C 语言中,
printf("%x")
用于以十六进制无符号整数形式输出数据。%x
格式说明符期望一个unsigned int
类型的参数。 - 当你传递一个有符号整数
-1
时,在进行格式化输出前,会发生整数提升和转换。有符号整数-1
在内存中以补码形式存储。对于一个 32 位系统,int
类型通常是 32 位,-1
的补码表示为所有位都为1
(即11111111 11111111 11111111 11111111
)。 - 当将这个补码值作为无符号整数处理并以十六进制输出时,每 4 位二进制对应一位十六进制数,
1111
对应十六进制的F
。
C
A
在常见编译器下,从右向左求值,n--
提供值 1
,++n
提供值 1
,最后 n
提供值 1
,所以输出结果为 1 1 1
。
三、简单c语言程序设计
scanf
函数
static
被调函数在主调函数之后定义,但被调函数的返回值是int或char,可以不对被调函数作声明(书上这样说的,但是不建议这样做)
文件
w强调打开的是新的文件,如果原本文件存在就清空内容,重新开始写入
数组题
7.12
7.13
动态分配二维数组
#include <stdio.h>
#include <stdlib.h>
int main() {
int rows = 3;
int cols = 4;
int i, j;
// 分配指针数组
int **arr = (int **)malloc(rows * sizeof(int *));
for (i = 0; i < rows; i++) {
// 为每一行分配内存
arr[i] = (int *)malloc(cols * sizeof(int));
}
// 初始化二维数组
for (i = 0; i < rows; i++) {
for (j = 0; j < cols; j++) {
arr[i][j] = i * cols + j;
}
}
// 输出二维数组
for (i = 0; i < rows; i++) {
for (j = 0; j < cols; j++) {
printf("%d ", arr[i][j]);
}
printf("\n");
}
// 释放内存,先释放每一行的内存,再释放指针数组的内存
for (i = 0; i < rows; i++) {
free(arr[i]);
}
free(arr);
return 0;
}
一些做题笔记
分析选项A:
- 全局变量作用域是从定义处到程序结束,若存在同名局部变量在其作用域内屏蔽全局变量。比如在函数内部定义了与全局变量同名的局部变量,此时在该函数内使用的是局部变量 。所以全局变量的作用域不一定比局部变量的作用域范围大,A选项错误。
分析选项B:
- 静态类别变量(包括静态全局变量和静态局部变量),它们在程序开始执行时分配内存,程序结束时释放内存。也就是说,其生存期贯穿于整个程序的运行期间。例如静态局部变量,它在函数调用结束后,其值依然保留,下次调用函数时,它使用上次调用结束时的值,这是因为它的生存期是整个程序运行期间,B选项正确。
分析选项C:
- 函数的形参只在函数被调用时才分配内存,在函数内部起作用,函数调用结束后,形参所占内存被释放。它属于局部变量,而不是全局变量,C选项错误。
分析选项D:
- 未在定义语句中赋值的auto变量的初值是随机值,因为auto变量是自动变量,存储在栈区,系统不会自动给它赋初值。而未在定义语句中赋值的static变量,系统会自动给它赋初值0(对于静态整型变量等数值型变量)或空字符(对于静态字符型变量 ),不是随机值。
9.
在C语言中,凡在函数中未指定存储类别的变量,其隐含的存储类别是自动(auto)。这是C语言的规定,自动变量存储在栈区,函数调用时分配内存,函数结束时释放内存。静态(static)变量需要显式声明;外部(extern)用于声明外部变量,引用其他文件中定义的全局变量;寄存器(register)变量建议编译器将变量存储在寄存器中,但现在编译器会自动优化,很少显式使用。所以答案选A。
另外,在早期的C语言代码中,对于一些简单的表达式,如果操作数没有明确的数据类型声明,编译器可能会按照默认规则将其当作 int 类型来处理,但这种写法不规范且容易引起混淆,在现代C语言编程中不建议使用。
如果函数的类型和return中表达式的类型不一致,以函数类型为准,先将表达式的值转换成函数类型后,再返回
10.
函数声明的一般形式为:函数类型 函数名(参数类型1 参数名1, 参数类型2 参数名2, …); 或者 函数类型 函数名(参数类型1, 参数类型2, …); 。
分析选项A:
- 在“double myadd(double a, b) ;”中,第二个参数只写了b,没有指定参数类型,不符合函数声明的语法要求,是错误的函数声明形式。
分析选项B:
- “double myadd(double, double ) ;”这种声明形式只指定了参数类型,省略了参数名,是合法的函数声明形式。
11.结构体
struct abc
{
int m;
int n;
} stype;
stype是用户定义的结构体变量名,可以直接使用。
如stype.m,stype.n
typedef struct NODE
{
int num; struct NODE *next;
} OLD;
OLD是一个结构体类型(相当于int的)
如:OLD Stu;
typedef int *INTEGER;
INTEGER p,*q;
- 对于变量 p :
- 根据 int *p 的定义, p 是一个指针变量,它指向的是 int 类型的数据,即 p 是基类型为 int 的指针变量。
- 对于变量 q :
- 由 *q 可知, q 本身也是一个指针变量,并且 q 指向的类型是 INTEGER 类型,而 INTEGER 是 int * ,所以 q 是指向指针(该指针指向 int 类型)的指针变量,即二级指针变量
一道例题
#include <stdio.h>
// 定义枚举类型表示星期
typedef enum {
Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
} Weekday;
// 定义结构体类型
typedef struct {
int year;
int month;
int day;
Weekday weekday;
} Date;
// 判断是否为闰年
int isLeapYear(int year) {
return (year % 4 == 0 && year % 100!= 0) || (year % 400 == 0);
}
// 计算从1980年1月1日到输入日期的天数
int countDays(Date d) {
int days = 0;
for (int y = 1980; y < d.year; y++) {
days += isLeapYear(y)? 366 : 365;
}
int months[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
for (int m = 1; m < d.month; m++) {
if (m == 2 && isLeapYear(d.year)) {
days += 29;
} else {
days += months[m];
}
}
days += d.day;
return days;
}
// 根据天数计算星期
Weekday calculateWeekday(int days) {
int offset = days % 7;
Weekday base = Tuesday;
return (Weekday) ((base + offset) % 7);
}
// 输出星期的英文名称
void printWeekday(Weekday w) {
switch (w) {
case Monday:
printf("Monday");
break;
case Tuesday:
printf("Tuesday");
break;
case Wednesday:
printf("Wednesday");
break;
case Thursday:
printf("Thursday");
break;
case Friday:
printf("Friday");
break;
case Saturday:
printf("Saturday");
break;
case Sunday:
printf("Sunday");
break;
}
}
int main() {
Date inputDate;
printf("请输入年份: ");
scanf("%d", &inputDate.year);
printf("请输入月份: ");
scanf("%d", &inputDate.month);
printf("请输入日期: ");
scanf("%d", &inputDate.day);
int totalDays = countDays(inputDate);
inputDate.weekday = calculateWeekday(totalDays);
printf("%d-%d-%d ", inputDate.year, inputDate.month, inputDate.day);
printWeekday(inputDate.weekday);
return 0;
}
12.共用体
union u_type {
int i;
char ch;
float a;
} temp;
temp.i = 266;
printf("%d", temp.ch);
266的二进制数为 100001010,char占一字节故提取后八位得到10
💡解答
理解共用体(union)的存储特点:
- 共用体的所有成员共享同一段内存空间。在本题中, union 类型 a 中, int x 和结构体 struct {char c; char d; }b 共享同一段内存。
- 一般在多数系统中, int 类型占 4 个字节(这里假设为 4 字节系统), char 类型占 1 个字节。对于结构体 b ,其成员 c 和 d 共占 2 个字节,它们共同使用 a.x 所占用 4 字节内存中的一部分。
- 由于计算机存储多采用小端存储模式(即低字节存低地址,高字节存高地址),这里我们按小端模式分析。
分析 a.x = 0x1234 的内存存储情况:
- 0x1234 用二进制表示为 0001 0010 0011 0100 (16 进制每一位对应 4 位二进制)。在 4 字节存储中(假设 int 占 4 字节),按小端模式存储,低地址存放低字节。
- 即内存中从低地址到高地址依次为 34 12 00 00 (这里补全 4 字节)。
确定 a.b.c 和 a.b.d 的值:
- 结构体 b 中, a.b.c 对应低地址的第一个字节, a.b.d 对应低地址的第二个字节。
- 从前面分析的内存存储 34 12 00 00 可知, a.b.c 的值为 0x34 , a.b.d 的值为 0x12 。
所以,①处应填 0x34 ,②处应填 0x12 。
计算
若x=0123,则表达式(5+(int)(x))&(-2)的值是
首先,分析 x = 0123 :
- 在C语言中,以 0 开头的整数表示八进制数。所以 0123 是八进制数,将其转换为十进制数。根据八进制转换为十进制的方法:0123 = 83。
然后,计算 (5+(int)(x)) :
- 因为 x 的值为八进制数 0123 (十进制是 83 ), (int)(x) 就是 83 ,那么 5+(int)(x)=5 + 83 = 88 。
接着,分析 -2 的二进制补码表示:
- 正数的补码等于原码,负数的补码是其绝对值的原码取反加 1 。
- 2 的原码(假设为 8 位): 00000010 。
- 取反: 11111101 。
- 加 1 : 11111110 ,这就是 -2 的补码。
再将 88 转换为二进制补码(假设为 8 位):
- 88 的原码为 01011000 ,正数的补码等于原码,所以 88 的补码也是 01011000 。
最后,进行按位与运算 (5+(int)(x))&(-2) ,即 01011000&11111110 :
- 按位与运算规则是:当两个操作数的对应位都为 1 时,结果位才为 1 ,否则为 0 。
- 01011000&11111110 = 01011000 (结果的二进制),转换为十进制是 88 。
所以,表达式 (5+(int)(x))&(-2) 的值是 88 。
逗号表达式
(a=3*5,a*3),a+5
下一步:45,a+5
最终表达式值为20