基础
OVERVIEW
一、数据类型
1.常变量:
- 常量:
常量 | 说明 |
---|---|
整型常量 | 如1000, 12345, 0, -1都是整型常量 |
实型常量 | 如3.14, -12.56, 12.34e3(e之前必须有数字,e之后必须为整数) |
字符常量 | 包括普通字符 ‘A’ 、与转义字符’ \t ’ |
字符串常量 | “string” |
符号常量 | #define PI 3.1415926 |
注:符号常量与变量不同,符号常量不占内存,在预编译后该符号就不存在了(不能赋值),其常用大写表示。
- 变量:
变量代表一个有名字和具体属性的存储单元,
在对程序进行编译链接时,由编译系统给每一个变量名分配对应的内存地址,
从变量中取值,实际上是通过变量名找到相应的内存地址,从该存储单元中读取数据。
- 常变量:
const int a = 3;
对比 | 说明 |
---|---|
常变量与常量 | 常变量具有变量的基本属性:类型、占存储单元,而常量没有名字(不能在程序中被引用) |
常变量与符号常量 | 符号常量是预编译指令,其只是用符号常量替代一个字符串,对符号常量的名字是不分配存储单元的。 |
常变量需要占用存储单元,常变量具有符号常量的优点且使用方便。 |
- 标识符:
用来对变量、符号常量名、函数、数组、类型等命名的有效字符序列,称为标识符。
注:编译系统将大写与小写字母认为是两个不同的字符,因此sum和SUM时两个不同的变量名。
2.INT:
- 基本整型int:
int数据类型占2字节 或 4字节,具体由C编译系统决定。
在存储单元的存储方式:用整数的补码(complement)形式存放,正数的补码就是该数的二进制形式,负数的补码为二进制取反加1。
在存放整数的存储单元中,最左边一位用于表示符号。若该位为0则为整数,若该位为1则为负数。
若整型变量分配2个字节,则存储单元中能存放的最大值为0111 1111 1111 1111(2^15-1),最小值为1000 0000 0000 0000(-2^15)
若整型变量分配4个字节,则存储单元中能存放的最大值为0111 1111 …. 1111(2^31-1),最小值为1000 0000 …. 0000(-2^31)
int衍生 | 说明 |
---|---|
短整型short int | 使用Visual C++6.0编译系统分配给int数据类型4个字节,short int 2个字节,范围为-2^15 ~ 2^15-1 |
长整型long int | long int 4个字节,范围为-2^31 ~ 2^31-1 |
双长整型long long int | long long int 8个字节,范围为-2^63 ~ 2^63-1 |
注:C标准只要求long型数据长度不短于int,short不长于int类型,并没有具体规定各种类型数据所占用的存储单元长度。
- sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)
3.CHAR:
-
由于字符是按其代码形式存储的,因此C99把字符型数据作为整数类型的一种。
printf("%d %c", c, c);
-
在C中指定用1个字节存储1个字符,所有系统都不例外,此时字节中的第一位置为0。
-
如果将1个负数赋值给有符号字符型变量是合法的
signed char c = -6
,但其不是一个字符,而作为1字节整型变量存储负整数。 -
若未规定按unsigned还是signed char处理,则由编译系统决定,这是与其他整型变量处理方法不同的地方。
char c = 255; printf("%d\n", c);
4.DOUBLE:
在存储时系统将实型数据分为小数部分和指数部分,小数部分的小数点前面的数字为0。
小数部分占的位数越多,数的有效数字越多精度也就越高。指数部分占的位数越多,表示的数值范围也就越大。
二、输入/出
1.printf
- %d:用于输出一个有符号的十进制整数
- %5d:在格式声明中指定输出数据的域宽,指定输出占5列,输出数据在此5列区域的右侧
- %ld:输出为长整型数据,
- %lld:输出为双长整型数据
- %c:用于输出一个字符
- %5c:在格式声明中指定输出数据的域宽,指定输出占5列,输出数据在此5列区域的右侧
- %c:输出字符y,如果整数太大,则将其最后一个字节的信息以字符形式输出
- %s:用于输出一个字符串
- %f:用于输出实数,以小数形式输出。默认输出整数部分全部,小数部分输出6位。
- %7.2f:指定输出数据占7列,其中包括2位小数,对最后一位采取四舍五入方法处理。
- %f:在使用该格式输出时要注意数据本身能提供的最大有效数字,float为6位有效数字,double为15位有效数字。
- %-7.2f:向左对齐
- %e:以指数形式输出实数,默认小数位为6位,指数部分占5列,数值按标准化指数形式输出(小数点前必须有且只有1位非零数字)
- %m.ne:指定输出格式
- %o:以八进制数形式输出
- %x:以十六进制数形式输出
- %u:用于输出无符号型数据,十进制整数形式输出
- %g:用于输出浮点数,系统自选f格式或e格式输出
2.scanf
三、数组
1.定义
-
类型符 数组名[常量表达式];
int a[10];
-
常量表达式是用来指定数组元素个数的,下标是从0开始的。
-
常量表达式可以包括常量和符号常量,不能包含变量,C语言不允许对数组的大小作动态定义。
-
如果在被调函数中定义数组,其长度可以是变量或非常量表达式的。
void func(int n) { int a[2*n];//合法 }
在完成数组定义后并对其赋值,就可以引用数组中的元素了(只能引用数组元素,而不能一次整体调用整个数组全部元素的值)。
2.字符数组
用来存放字符数据的数组是字符数组,字符数组中的一个元素存放一个字符。char c[10];
在C语言中式将字符串作为字符数组来处理的,并规定了一个字符串结束标志 \0
空操作符。
字符数组并不要求最后一个字符为\0
,甚至可以不包括\0
- %c:逐个字符进行输入输出
- %s:整个字符串一次输入输出
四、函数
1.数组作函数参数
凡是变量可以出现的地方,数组元素可以作函数实参传递,数组名也可以作实参和形参传递数组的第一个元素。
- 数组元素作函数实参:数组元素可作为实参,但不能作形参(形参是在函数被调用时临时分配存储单元的,数组元素不能)
- 数组名作函数参数:用数组名作参数传递的是数组首个元素的地址。
- 只有数字首元素地址的传递,实参数组的大小不会被传递
- 形参数组可以不指定大小,在定义数组时后面加上空的方括号即可
[]
- 多维数组名作函数参数:在调用函数对形参数组定义时,可以省去第一维的大小说明,但是第二维不能省略。
2.变量的存储方式
从变量的作用域来可以将变量分为局部变量和全局变量,
从变量在内存中的存储方式来可以分为静态存储方式和动态存储方式,
在C语言中每一个变量和函数都有两个属性,数据类型(整型、浮点型)和数据的存储类别(静态存储、动态存储)
C的存储类别包括4种:auto自动、static静态、register寄存器、extern外部的,根据存储类别可知道变量的作用域和生存期。
(1)auto:
局部变量如果不专门声明为static,则都是动态的分配存储空间的,数据存储在动态存储区中(关键字auto可以省略)。
(2)static:
- 静态局部变量属于静态存储类别,在静态存储区内分配存储单元,在程序整个运行期间都不释放。
- 对静态局部变量是在编译时赋初值的,即只赋值1次。
- 如果在定义局部变量时不赋值,则对静态局部变量来说,编译时自动赋初值0或空字符
\0
(若为auto则值不定)
注:不要误认为对外部变量加static声明后,其才采用静态存储的方式(存放在静态存储区中),而不加static则采用动态存储。
- 对于局部变量来说,声明存储类型的作用是指定变量存储的区域(静态or动态存储区),以及生存期的问题。
- 对于全局变量来说,由于都是编译时分配内存,故都是存放在静态存储区中,声明存储类型是指定变量作用域的扩展问题。
(3)register:
若有一些变量使用频繁,允许将局部变量值放在CPU寄存器中提高执行效率。
(4)extern:
- 在一个文件中扩展外部变量的作用域:
一般情况下,外部变量是在函数的外部定义的全局变量,其作用域是从变量的定义处开始,到该程序文件的末尾。
若在定义点之前的函数需要引用该外部变量,则可以使用extern关键字对该变量做外部变量声明,表示把该外部变量的作用域扩展到此。
#include <stdio.h>
int main() {
int max();
extern int A, B, C;//将外部变量ABC的作用域扩展到此处开始
printf("please enter three integer numbers:");
scanf("%d %d %d", &A, &B, &C);
printf("max is %d\n", max());
return 0;
}
int A, B, C;
int max() {
int m;
m = A > B ? A : B;
if (C > m) m = C;
return m;
}
- 将外部变量的作用域扩展到其他文件:
若一个程序包含两个文件,在两个文件中都要用到同一个外部变量num,不能分别在文件中各自定义。
这时应该在任意一个文件中定义外部变量num,在另一个文件中使用extern对num做外部变量声明,即extern num;
在编译和链接时系统会由此知道num有外部链接,去别处找到已定义的外部变量num,将作用域扩展到本文件。
//file1.c
#include <stdio.h>
int A;
int main() {
itn power(int);
int b= 3;
int c, d, m;
printf("enter the number a and its power m:\n");
scanf("%d, %d", &A, &m);
c = A * b;
printf("%d * %d = %d\n", A, b, c);
d = power(m);
printf("%d ** %d = %d\n", A, m, c);
return 0;
}
//file2.c
extern A;//将file1.c文件中已定义的外部变量作用域扩展到本文件中
int power(int n) {
int ans = 1;
for (int i = 1; i <= n; ++i) ans *= A;
return ans;
}
- 将外部变量的作用域限制在本文件中:
有时希望某些外部变量只限于被本文件引用,而不能被其他文件引用,这时可以在定义外部变量时加一个static声明。
这种加上static声明,只能用于本文件的外部变量称为静态外部变量。
//file1.c
static int A;
int main() {
...
return 0;
}
//file2.c
extern A;
void func(int n) {
A = A * n;//报错禁止引用
...
}
(5)存储类别小结:
3.内部函数与外部函数
根据函数是否能被其他源文件调用,可以将函数分为内部函数和外部函数。
(1)内部函数:
static int func(int a, int b)
使用内部函数可以使函数的作用域只局限于所在文件,这样在不同的文件中即使有同名的内部函数,也不会相互干扰。
(2)外部函数:
extern int func(int a, int b)
如果在定义函数时省略extern则默认为外部函数。
在需要调用此函数的其他文件中,也需要对此函数作声明,声明时要加关键字extern表示该函数是在其他文件中定义的外部函数。
//file1c
#include <stdio.h>
int main() {
//函数原型声明 extern可省略
extern void enter_string(char str[]);
extern void delete_string(char str[], char ch);
extern void print_string(char str[]);
char c;
char str[80];
enter_string(str);
scanf("%c", &c);
delete_string(str, c);
print_string(str);
return 0;
}
//file2.c
void enter_string(char str[80]) {
gets(str);//向字符数组输入字符串
}
//file3.c
void delete_string(char str[], char ch) {
int j = 0;
for (int i = 0; str[i] != '\0'; ++i)
if (str[i] != ch) str[j++] = str[i];
str[j] = '\0';
}
//file4.c
void print_string(char str[]) {
printf("%s\n", str);
}
注:函数原型能够把函数的作用域扩展到定义该函数的文件之外,只要在文件中包含该其函数原型即可,如
#include<math.h>
。