基本数据类型
分为:整型、浮点型、指针和聚合类型(数组和结构等)
整型
整型:字符型、短整型、整型、和长整型,都分为有符号(signed)和无符号(unsigned)
规则:
长整型至少应该和整型一样长,而整型至少和短整型一样长。
short int至少16位,即至少2个字节,long int至少32位,即至少4个字节,至于中间的int为运行机器的最为自然的位数。即32位的机器,int和long int 一样
bytes.cpp
//64位的机器
#include "stdafx.h"
#include "stdlib.h"
int main()
{
printf("Char : %d\n", sizeof(char)); //1
printf("Unsigned Char: %d\n", sizeof(unsigned char));//1
printf("Short Int : %d\n", sizeof(short int )); //2
printf("Short Int : %d\n", sizeof(unsigned short int)); //2
printf("Int : %d\n", sizeof(int)); //4
printf("Unsigned Int : %d\n", sizeof(int)); //4
printf("Long Int : %d\n", sizeof(long int)); //4
printf("Unsigned Long Int : %d\n", sizeof(unsigned long int)); //4
printf("Long Long Int : %d\n", sizeof(long long int)); //8
printf("Unsigned Long Long Int : %d\n", sizeof(unsigned long long int)); //8
system("pause");
return 0;
}
整型字面值
字面值是字面值常量的缩写
字符常量总是int类型,不能在它们后面添加unsigned或long后缀。字符常量就是一个用单引号包围起来的单个字符:
如’M’ ‘\n’等
如果一个多字节字符常量的面前有一个L,那么它就是宽字符常量
如L’x’ L’e^’
枚举类型
枚举类型本质是常量,某种程度上就是宏定义
如果#define定义周一到周日,会显得冗余,故使用枚举类型
enum typeNmae{valueName1,valueName2,....};
//valueName1默认为0,后面的值依次递增
//定义
enum week{Mon=10,Tues=12,Wed,Thurs,Fri}; //10 12 13 14 15
enum week a = Mon, b=Fri;
enum.cpp
#include "stdafx.h"
#include "stdlib.h"
int main()
{
enum week {Mon = 10,Tues = 12, Weds,Thurs,Fri};
enum week a = Mon, b = Thurs;
int m, n;
m = Weds;
n = Fri;
printf("a is %d\n", a); //10
printf("b is %d\n", b); //14
printf("Mon is %d\n", Mon); //10
printf("Fri is %d\n", Fri); //15
printf("m is %d\n", m); //13
printf("n is %d\n", n); //15
system("pause");
return 0;
}
//Mon这些都是常量,其值不能修改
浮点类型
分为float 、double、long double类型
默认情况下为double,除非3.14f这种表示float,3.14l表示long double
标准规定:long double至少和double一样,double至少和float一样,类似整型那种感觉,所有浮点类型至少能够容纳从10^-37
到 10^37之间的任何值
bytes.cpp
//64位的机器
#include "stdafx.h"
#include "stdlib.h"
int main()
{
printf("Float : %d\n", sizeof(float)); //4
printf("Double : %d\n", sizeof(double)); //8
printf("Long Double :%d\n", sizeof(long double)); //8
system("pause");
return 0;
}
指针
指针常量
其实c语言内部没有这个概念,因此除了NULL指针可以用零值表示外,其他指针使用类似0xff2044ec这样的字面值来表示几乎没有用处,因为存放变量的地址只有程序运行的时候才能确定
字符串常量
字符串常量是一串以NUL字节结尾的零个或多个字符。很多编译器禁止修改其值。如果需要修改字符串请将其存储于字符数组中。
因为程序使用字符串常量会生成一个“指向字符的常量指针”。当一个字符串常量出现在一个表达式中,表达式所使用的值就是这些字符串的地址(即指针),而不是这些字符本身。
可以把字符串常量赋值给一个“指向字符的指针”,但是不能将字符串常量赋值给一个字符数组,因为字符串常量的直接值是一个指针,而不是这些字符本身。
pointer.cpp
#include "stdafx.h"
#include "stdlib.h"
int main()
{
char *str = "This is string!";
printf("%d\n",sizeof(char *));
printf("%d\n", sizeof(str));
printf("%d\n", sizeof(*str));
printf("%d\n", str); //str表示一个地址,该地址指向字符串This is string!NUL的首地址 每次程序运行都不一样
printf("%d\n", &str); //&str表示指向str地址的地址,每次程序运行都不一样
printf("%d\n", *&str); //和str结果一样,通过*获取指向str地址的地址的值就是str地址本身
printf("%d\n", *str); //84 ascii表示T
printf("%c\n", *str); //*str 表示获取str地址指向的值T
printf("%s\n", str); //str表示一个地址,该地址指向字符串This is string!NUL,%s表示获取该地址指向的所有值,即整个字符串
system("pause");
return 0;
}
基本声明
整型类型在缺省情况下都是有符号数。至于char是否是signed,要看编译器,所以signed一般常用于char
初始化
int a = 100;
声明简单数组
int a[20];表示数组下标从0开始,一直存储到19的数组
计算数组大小
#include "stdafx.h"
#include "stdlib.h"
int main()
{
int a[20] = {1,3};
printf("0x%x\n",a); //表示数组首地址
printf("0x%x\n", &a); //表示数组的整个地址,首地址和数组的整个地址在值上是一样的,指向同一个地方,但意义不同,一个指向1,一个指向全部
printf("0x%x\n", a+1); //表示数组偏移+1 即第一位的地址,此时是3的地址
printf("0x%x\n", &a+1); //表示数组整体偏移+1 即加上4*20=80
printf("%d\n",*a); //表示1
printf("0x%x\n", *&a); //表示访问&a地址指向的值
printf("0x%x\n", *&a + 1); //表示数组第二个值的地址
printf("%d\n", *a + 1); //表示1+1=2
printf("%d\n", *(a + 1)); //表示3
system("pause");
return 0;
}
隐式声明
部分编译器会自动帮你识别出变量的类型,和函数的类型,可以不用声明,这就是个傻缺功能,很多编译器并不支持,强烈建议不要使用隐式声明,本来就是个错误语法,编译器帮你改正了,这样可不好,到别的编译器就会报错,别人看你的代码也会产生问题。
typedef
与define的区别是:define用于定义常量,无法正确处理指针类型
typedef更适合用于定义指针类型
#define MAX 1000 //合适
#define char* point_char
point_char a,b; //a是一个char *,但b不是,b就是个字符
typedef char* point_char;
point_char a,b; //a和b都是char *
typedef.cpp
#include "stdafx.h"
#include "stdlib.h"
#define MAX 1000
typedef char * point_char;
point_char a, b;
int main()
{
printf("%d\n",sizeof(a));
printf("%d\n", sizeof(b));
system("pause");
return 0;
}
define.cpp
#include "stdafx.h"
#include "stdlib.h"
#define point_char char*
int main()
{
point_char a, b;
printf("%d\n",sizeof(a)); //4
printf("%d\n", sizeof(b)); //1
system("pause");
return 0;
}
常量
int const a = 0;
const int a = 0; //两者写法都是可以,没有什么不同,都为常量,不可修改其值
常量相关混乱的地方
int *p; //表示指向整型的指针
int const *p; //表示指向整型常量的指针,指针地址可以修改,但其中地址指向的值不能修改
int * const p; //表示该指针为一个常量,它指向的值可以修改,但该指针地址不能修改
int const *const p; //表示指针和它指向的值都不能修改
指针初始化及赋值
#include "stdafx.h"
#include "stdlib.h"
int main()
{
int a,b,c;
a = 15;
b = 20;
c = 25;
int *p = &a;
printf("%p\n", p);
printf("%d\n", *p); //15
*p = 30;
printf("%d\n", *p); //30
printf("%d\n", a); //30
system("pause");
return 0;
}
指向整型“常量”的指针
#include "stdafx.h"
#include "stdlib.h"
int main()
{
int a,b,c;
a = 15;
b = 20;
c = 25;
int const *p = &a; //此时通过*p = 20这种方式无法修改a的值,但是可以更改p的地址
a = 20;
printf("%p\n", p);
printf("%d\n", *p); //20
printf("%d\n", a); //20
p = p + 1; //可以更改p的值
printf("%p\n", p);
printf("%d\n", *p);
printf("%d\n", a); //20
system("pause");
return 0;
}
表示指针为常量
#include "stdafx.h"
#include "stdlib.h"
int main()
{
int a,b,c;
a = 15;
b = 20;
c = 25;
int * const p = &a; //此时p的值不能修改
a = 20;
printf("%p\n", p);
printf("%d\n", *p); //20
printf("%d\n", a); //20
*p = 30;
printf("%p\n", p);
printf("%d\n", *p);
printf("%d\n", a); //30
system("pause");
return 0;
}
值和指针都不能修改
#include "stdafx.h"
#include "stdlib.h"
int main()
{
int a,b,c;
a = 15;
b = 20;
c = 25;
int const * const p = &a; //此时通过*p = 20这种方式无法修改a的值,p = P+1的方式也不能修改a的值,但是可以通过a =20来修改
a = 20;
printf("%p\n", p);
printf("%d\n", *p); //20
printf("%d\n", a); //20
printf("%p\n", p);
printf("%d\n", *p);
printf("%d\n", a); //20
system("pause");
return 0;
}
作用域
文件作用域(file scope)
在所有代码块之外声明的标识符都有文件作用域,表示这些标识符从它们的声明之处直到它所在的源文件结尾处都是可以访问的
原型作用域(prototype scope)
只适用于在函数原型中声明的参数名。
函数作用域(function scope)
只适用于语句标签,语句标签用于goto语句。一个函数中的所有语句标签必须唯一。