1、C开发环境:
使用的软件:DEVCPP_skycn.exe
2、HelloWorld.c 编写:
#include
int main(int argc, char args[]){
printf("hello world");
system("pause");
return 0;
}
c语言可以调用window指令。
例如eclipse.exe就是启动jar包来启动应用的。eclipse是java编写的
查看eclipse.ini里面
-startup
plugins/org.eclipse.equinox.launcher_1.3.0.v20140415-2008.jar
就是调用这个jar文件启动的
所以我们c程序调用java代码就可以
system("java Hello_World");
3、C的基本数据类型:
byte
short 2个字节
int 4个字节
long 4个字节
float 4个字节
double 8个字节
char 1个字节
boolean
例如:
main(){
signed int i = 3;
//无符号只是注明最高位是数值位,但不会改变二进制表示的取值
unsigned int i2 = 4200000000;
char c = 'a';
long long ago = -420000000;
printf("i的值为%d\n", i);
printf("i2的值为%u\n", i2);
printf("c的值为%c\n", c);
printf("short的长度为%d\n", sizeof(short));
printf("int的长度为%d\n", sizeof(int));
printf("long的长度为%d\n", sizeof(long));
printf("float的长度为%d\n", sizeof(float));
printf("double的长度为%d\n", sizeof(double));
printf("char的长度为%d\n", sizeof(char));
printf("long long的长度为%d\n", sizeof(long long));
printf("long int的长度为%d\n", sizeof(long int));
printf("short int的长度为%d\n", sizeof(short int));
system("pause");
}
注意:
int数据:4个字节,32位。能表示的数字是 2的32次方(4294967296) 个数字
取值范围:0 ~ 2的32次方-1 (0~4294967295)
如果最高位取出来作为符号位,用于表示正负,不再表示数值,剩下31个数值位。
符号位如果为0,31个数值位表示的数字是正数。
符号位如果为1,31个数值位表示出来的是负数。
结合符号位,int型的取值范围 -2的31次方 ~ 2的31次方-1(-2147483648 ~ 2147483647)
原反补码问题
计算机是存储的补码。
正数原反补是一样的
原码:二进制表示
反码:除最高位,其他位依次取反
补码:反码+1
例如:
5的源码:0000 0101
-5的源码:1000 0101
-5的反码:1111 1010
-5的补码:1111 1011
所以计算机存储的就是1111 1011
4、C的输出函数和输入函数:
输出函数:printf("%d\n", i);
%d - int
%ld – long int
%lld - long long
%hd – 短整型
%c - char
%f - float
%lf – double
%u – 无符号数
%x – 十六进制输出 int 或者long int 或者short int
%o - 八进制输出
%s – 字符串
注意:
C语言中的字符串是字符数组
//字符数组末尾一定有一个结束符“\0”
char str[] = "hello";
printf("%s\n", str);
输入函数:scanf("%d", &count);
例如:
main(){
printf("请输入班级人数:");
int count;
//取出count的内存地址,把用户输入的数据保存在这个地址上
scanf("%d", &count);
printf("请输入班级名称:");
//定义字符数组,必须指定长度
//C的数组不检测越界
char name[7];
scanf("%s", &name);
printf("count的地址为%#x\n", &count);//取地址符
printf("name的地址为%#x\n", &name);
printf("班级人数为:%d,班级名称为%s\n", count, name);
system("pause");
}
注意:
C语言中,定义数组只能 char name[4]; 不能把[]写在前面,和java不一样
C语言中数组不存在越界异常,但是我们不要越界,因为可能导致其它数据异常,
因为越界的数据会占用其它数据的内存。
5、内存地址:
内存中所有数据都是通过地址拿到的,没有地址的内存是无法访问。
例如:
int i;
i = 10;
printf("%d\n", i);
printf("%#x\n", &i);
打印:
10
0x28ff1c
6、指针:
为什么要使用指针:
可以直接访问硬件,可以操作硬件的内存,修改数据。
可以返回一个以上的值
int i;//申请了4个字节的内存
i = 3;//赋值
int* p = &i;//定义一个指针变量,指向int类型的指针,p一定存的是地址
int** q = &p;//定义一个二级指针,q就是保存p的地址
printf("%d\n", i);//3
printf("%#x\n", &i);//0x28ff18 ,i变量的地址
printf("%#x\n", p);//0x28ff18,存的也是i变量的地址
printf("%d\n", *p);//3
printf("%d\n", **q);//3
printf("%#x\n", &p);//0x28ff14 , p这个指针变量的地址
printf("%#x\n", q);//0x28ff14, p这个指针变量的地址
注意:
指针在没有赋值之前,是不能给指向的那个数据赋值的。因为开始定义指针是随机指向一个数据。
有可能是指向系统关键数据,修改了就导致系统问题,所以不允许这样做
例如:
int* p ;
*p=10;//这样运行会挂掉,p现在是随机指向一个数据的
7、指针的使用:
在主函数中获取子函数的变量地址
void function(int* p){
int i = 3;
p = &i;
printf("子函数打印地址%#x\n", &i);
}
main(){
int* mainp;
function(mainp);
printf("主函数打印地址%#x\n", mainp);
system("pause");
}
这样是不行的,因为mainp这个变量占用一个内存,这个时候没有赋值,随机指向个数据。mainp传递给p,
p这个时候也是和mainp指向的数据一样。p=&i,把p赋值了。这是mainp还是没有赋值,所以无效。
改造:使用二级指针
void function(int** p){
int i = 3;
*p = &i;
printf("子函数打印地址%#x\n", &i);
}
main(){
int* mainp;
function(&mainp);//传指针变量的地址
printf("主函数打印地址%#x\n", mainp);
printf("i的值为%d\n", *mainp);//拿到也是没有意义的,会销毁掉这个数据
system("pause");
}
注意:32位编译器,指针的长度是 4个字节(printf(“%d\n”,sizeof(int*));可以打印出来)
8、数组:
int main(){
//char c[] = "hello";
int c[] = {1,2,3,4,5};
printf("%#x\n", &c[0]); //0x28ff0c
printf("%#x\n", &c[1]); //0x28ff10
printf("%#x\n", &c[2]); //0x28ff14
printf("%#x\n", &c[3]); //0x28ff18
printf("%#x\n", c); //0x28ff0c ,字符数组的地址,就是一个字符的地址
int* p = c;
//c+1表示位移一个单位,一个单位是几个字节根据指针类型决定
printf("第0个元素的值%d\n", *(p + 0));
printf("第1个元素的值%d\n", *(p + 1));
printf("第2个元素的值%d\n", *(p + 2));
printf("第3个元素的值%d\n", *(p + 3));
printf("两个地址的距离%d\n", (p + 3) - (p + 1));
system("pause");
}
注意:数组的内存空间是连续的
9、栈和堆
int i;
Person p;
p = new Person();
栈是先进后出的,是一段连续的内存空间。
定义的变量首先在栈内存中被分配空间(系统自动分配的),单你new 了对象,就在堆内存中分配空间。
当你的p使用完,弹栈了,堆内存的Person对象就是没有任何引用了,就是垃圾数据,会被回收器回收。
栈内存:
内存空间是连续的
自动分配
大小固定
系统自动释放
栈上分配的内存叫静态内存
堆内存:
程序员手动申请
java:new
c:malloc
大小不固定,取决于系统虚拟内存
程序员手动释放
java:自动
c:free函数
空间不连续
堆上分配的内存叫动态内存
10、申请内存:
main(){
//申请12个字节的堆内存 ,此函数返回堆内存的首地址
int* p = malloc(3 * sizeof(int));
*(p + 1) = 3;
printf("%d\n", *(p + 1));
printf("%#x\n", p + 1);
//释放堆内存
free(p);
system("pause");
}
11、结构体:
void study(){
printf("自定义函数\n");
}
//结构体中不能定义函数,但是可以定义函数指针
struct student{
int age;
int height;
char sex;
void(*studyp)();//这个名称自己定义
};
int main(){
struct student stu = {20, 190, 'f', study};
printf("%d\n", stu.age);
//为了方便位移运算,结构体中各个属性的长度会被自动补齐
printf("%d\n", sizeof(stu));
//第一种调用方法,调用函数指针
stu.studyp();
//第二种调用方法
struct student* stup = &stu;
(*stup).studyp();
//第三种调用方法
//引用这个指针指向的结构体的属性
stup->studyp();//一般开发中这样写
system("pause");
}
12、共用体:
main(){
//共用体能表示这几种变量
union{int i; short s; char c;} un;
//共用体同时只能赋一个值,新值会覆盖旧值
//所以长度取决于最长的变量
un.i = 30;
printf("%d\n", un.i);
printf("%d\n", sizeof(un));
un.s = 20;
printf("%d\n", un.i);
printf("%d\n", sizeof(un));
system("pause");
}
打印的结果:
30
4
20
4
注意:同一时间,共用体只能存储一种数据。
13、枚举:
enum WeekDay
{
Monday = 1,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday
};
int main(void)
{
//int day;
//枚举作用:规定了变量的取值范围
enum WeekDay day = Thursday;
printf("%d\n",day);
system("pause");
return 0;
}
打印的结果是:4
14、自定义类型:
#include
#include
typedef int myint;
main(){
myint i = 3;
printf("%d\n", i);
system("pause");
}
打印结果:3
只是给int起了个别名,有什么用呢?
例如:在C:\Program Files (x86)\Java\jdk1.7.0_10\include\jni.h中
typedef unsigned char jboolean;
typedef unsigned short jchar;
typedef short jshort;
typedef float jfloat;
typedef double jdouble;
增加代码的可阅读性。