C Basic
// java数据类型 和长度int 4个字节 double 8个字节 float 4个字节 long 8个字节 // short 2个字节 boolean 1个字节 char 2个字节 byte 1个字节 // char, int, float, double, signed, unsigned, long, short and void // c语言中 数据类型比java少一些 在c语言中没有 boolean类型的数据 int 1 代表真 0 代表假 // c 语言中没有String类型的数据 java中表示一个字符串 String , c语言中表示字符串 通过char类型的数组来表示字符串 // c 语言没有byte类型 所有用char的类型表示byte类型 #include <stdio.h> #include <stdlib.h> // sizeof(); c语言的一个函数 可以把 某种数据类型的长度获取出来 int main() { // %d 类似sql语句的? 占位符 printf("char的长度为%d\n", sizeof(char)); printf("int的长度为%d\n", sizeof(int)); printf("float的长度为%d\n", sizeof(float)); printf("double的长度为%d\n", sizeof(double)); printf("long的长度为%d\n", sizeof(long)); printf("short的长度为%d\n", sizeof(short)); //signed, unsigned, 数据类型的修饰符 // signed int ; 代表的是有符号的int的数据 // unsigned int ; 无符号的int数据 printf("signed int的长度为%d\n", sizeof( signed int)); printf("unsigned int的长度为%d\n", sizeof( unsigned int)); // 符号的修饰符 只能修饰 整数类型的数据 long int // 不能修饰 浮点型的数据 float double // printf("signed float的长度为%d\n", sizeof( signed float)); system("pause"); // 调用windows下系统的命令 让程序暂停执行 方便观察程序的执行结果 }
/*%d - int %ld – long int %c - char %f - float %lf – double %x – 十六进制输出 int 或者long int 或者short int %o - 八进制输出 %s – 字符串 Int len; Scanf(“%d”,&len);*/ #include <stdio.h> // java import xxx.xx.pack 引用函数的声明 #include <stdlib.h> main() // 程序的入口函数 { int i = 3; float f = 3.1415; double d = 6.2815; char c = 'A'; //通过单引号定义字符 short s = 2; printf("int i=%d\n",i); printf("float f=%f\n",f); printf("char c=%c\n",c); printf("double d=%lf\n",d); printf("short s=%d\n",s); /*char arr[20] ; //定义一个长度为20的数组 scanf("%s",arr); // 从键盘接受一个字符串,放在c数组里面 printf("s =%s\n",arr); */ int j ; scanf("%d", &j);//&代表的是取地址 printf("j=%d\n",j); system("pause"); // 调用windows下系统的命令 让程序暂停执行 方便观察程序的执行结果 }
#include <stdio.h> #include <stdlib.h> main() { // 所有的变量都会分配一块内存空间 // 指针就是用来表示一块内存空间的地址的 // 地址可以用过 &这个符号获取到某个变量的在内存中的地址 // 这个地址如果想把他存放起来 就需要有一个变量 去存放这个地址 // 存放内存地址的变量 就是指针变量 // 指针和指针变量 // 指针是用来表示一块内存地址的, // 指针变量是用来存放一个内存地址的 . // printf("ready go! 剩余时间60秒\n"); int time = 60; printf("time变量对应的内存地址为%#X\n", &time); for(;time>0;time--){ printf("剩余时间%d\n",time); sleep(4000); } printf("游戏结束"); system("pause"); // 调用windows下系统的命令 让程序暂停执行 方便观察程序的执行结果 }
#include <stdio.h> #include <stdlib.h> main() { //指针是什么? 指针就是一个地址 //地址代表的就是一块内存空间 int i =5;// 定义一个int 类型的变量i 值 =5 printf("i的地址 %#X\n",&i); //获取i的地址 // &i; //定义一个指针变量 int* p ; // 指针变量 定义一个int* 类型的变量p //int *p, int * p; p = &i; // 就是把i的指针赋给指针变量p ,现在指针变量p里面存放的内容(数据) 就是i的地址 printf("p里面的内容为(i的地址) %#X\n",p); //*号 操作符 // *号的几种含义 //1 . *号放在某种数据类型的后面,代表就是这种数据类型的指针 int* float* //2 . *号 代表一个乘法符号 3*5 = 15; //3 . *号放在一个指针变量的前面 -> 代表取这个指针变量所存放的地址里面对应的数据 printf("i=%d\n",i); printf("*p的值%d\n",*p); // 改变p的值 会不会影响i的值? //p = NULL; // printf("i=%d\n",i); // 改变i的值 会不会影响p的值? // i = 100; // printf("p里面的内容为(i的地址) %#X\n",p); // 通过上述实验 p和 i 是两个不同的变量 ,改变i的值 不会影响 p的值,同理,更改p的值 也不会影响i的值 // 更改*p的值 会不会影响i的值 // *p = 88; // printf("i=%d\n",i); // 更改i的值 会不会影响 *p的值呢? // i = 99; // printf("*p的值%d\n",*p); //*p 和i 其实代表的是同一个变量,代表是同一块内存空间 system("pause"); // 调用windows下系统的命令 让程序暂停执行 方便观察程序的执行结果 }
#include <stdio.h> #include <stdlib.h> main() { /* int* p; //定义一个指针变量 垃圾值 -> 野指针 //printf("*p=%d\n",*p); *p = 1231; // 立刻蓝品 // 指针变量如果没有赋值就不能使用 */ /* int d = 324233; char* c; ; // 编译错误 不符合的指针类型 c = &d; printf("*p = %c\n",*c); 类型不相同的指针不可以互相转换 */ system("pause"); // 调用windows下系统的命令 让程序暂停执行 方便观察程序的执行结果 }
#include <stdio.h> #include <stdlib.h> f(int** q){ int i = 3; printf("子函数 i的地址 %#X\n",&i); // *q 代表的就是p变量 *q = &i; } /** 使用指针的时候 不可以访问已经被系统回收掉的数据 子函数执行完毕后 子函数里面所有的局部变量都会别系统回收 */ main() { // 希望在主函数里面去使用子函数里面的变量 i // f(); // 希望在主函数里面得到子函数 里面int i变量的地址 int* p ; //存放子函数f中 int i的地址的一个变量 f(&p); // printf("主函数 i的地址 %#X\n",p); // printf("i的值为 %d\n",*p); system("pause"); // 调用windows下系统的命令 让程序暂停执行 方便观察程序的执行结果 }
#include <stdio.h> #include <stdlib.h> // public List<Person> getPersons() {}; // public byte[] getbytes(){}; /* 如果让子函数 更改主函数里面的数据 如何让子函数 返回一个以上的值 1.子函数的形参 为 主函数中要修改的变量的地址 2. 调用子函数的时候 把要修改的变量的地址 传递给子函数 3. 在子函数里面 修改这个地址里面存放的变量的内容 4. 主函数使用这个变量的时候 里面的值就发生了变化 */ int f(int* p, int* q){ *p = 33; *q = 55; } main() { int i = 3; int j = 5; f(&i,&j); printf("i=%d\n",i); printf("j=%d\n",j); system("pause"); // 调用windows下系统的命令 让程序暂停执行 方便观察程序的执行结果 }
#include <stdio.h> #include <stdlib.h> main() { char arr[20] ={'h','e','l','l','o','\0'}; // 利用char类型指针 方便的表示一个字符串 char* arr1= "hello world"; printf("%s",arr1); system("pause"); // 调用windows下系统的命令 让程序暂停执行 方便观察程序的执行结果 }
#include <stdio.h> #include <stdlib.h> // 数组是一块连续的内存空间 数组名 就是内存空间的首地址 // 数组名[i] == *(数组名+i); main() { /* char[] arr = new char[20]; char arr[] ; */ // 创建一个长度为5的int类型的数组 int arr[5] ={1,2,3,4,5}; printf("a[0]=%d\n",arr[0]); printf("a[4]=%d\n",arr[4]); // 逻辑上是错误的代码 数组下标越界 // printf("a[5]=%d\n",arr[5]); // windows xp 缓冲区越界补丁 // arr是一个什么东西呢? printf("arr = %#X\n",arr); // 打印 数组的第一个元素的地址 printf("arr[0]地址 = %#X\n",&arr[0]); // 打印数组中的第二个元素 printf("arr[1]=%d\n",arr[1]); printf("arr[1]=%d\n", *(arr+1)); //问题: arr[i] *(arr+i) 代表的是同一个变量么? // 代表的是同一块内存空间 指向的是同一个变量 //通过实验 : 数组名表示的 就是这个数组第一个元素 的首地址 system("pause"); // 调用windows下系统的命令 让程序暂停执行 方便观察程序的执行结果 }
#include <stdio.h> #include <stdlib.h> #define pi 3.1415 // 写一个子函数 打印数组里面的每一个元素 void printArr(int* arr, int len){ // arr是数组的首地址 len数组的长度 int i=0; for(;i<len;i++){ // 在c99 的语法格式下 for循环的初始化条件 不能写在 for 循环的括号里面 // printf("arr[%d]=%d\n",i,arr[i]); // arr[i] 和 *(arr+i) 代表的含义相同 printf("arr[%d]=%d\n",i, *(arr+i)); } } main() { // int arr[10]={1,2,3,4,5}; // printArr(&arr[0],10); //1 .定义一个数组 缺陷 数组的长度 必须事先申请好 //int arr[1000]; // 这一句代码一旦执行 ,就立刻会在内存里面申请 5个内存空间 每个内存空间的大小可以存放一个int类型的数据 // 没有办法动态的增加这一块空间的大小, 也没办法减小这一块内存空间 //2. 循环赋值 //3. 打印数组里面的内容 int* arr = (int* )malloc(sizeof(int)*10); arr = realloc(arr,sizeof(int)*8); //空间的长度为12了 int i =0; for(;i<5;i++){ printf("请输入arr[%d]=的值\n",i); scanf("%d",arr+i); } printArr(arr,5); system("pause"); // 调用windows下系统的命令 让程序暂停执行 方便观察程序的执行结果 // 作业: 从键盘接受一个数组 数组的大小 // 动态的更改 数组的大小增加2 }
#include <stdio.h> #include <stdlib.h> main() { int i =3; //天津的某个路上 盖了一个房子 3 int j =5; // 北京的某个路上 盖了一个方法 5 int* p = &i; // p 天津的门牌号 int* q = &j; // q 北京的门牌号 // 指针的运算和数组都是紧密关联的 char arr[5]={'a','b','c','d','e'}; //一块连续的内存空间 char* p1 = &arr[2]; printf("char = %c\n", *(p1-1)); // char 内存中占用 1个字节 // int 内存 中占用 4个字节 int intarr[5]={1,2,3,4,5}; //一块连续的内存空间 int* q1 = &intarr[2]; printf("char = %d\n", *(q1-1)); // 指针的运算 按照 约定好的数据类型 偏移相对应的内存空间的大小 system("pause"); // 调用windows下系统的命令 让程序暂停执行 方便观察程序的执行结果 }
#include <stdio.h> #include <stdlib.h> main() { int i =3; double d = 3.141692; float f = 3.1423; char c ='B'; int* ip = &i; double* dp = &d; float* fp = &f; char* cp = &c; printf("int 类型指针变量的长度为 %d\n",sizeof(ip)); printf("double 类型指针变量的长度为 %d\n",sizeof(dp)); printf("float 类型指针变量的长度为 %d\n",sizeof(fp)); printf("char 类型指针变量的长度为 %d\n",sizeof(cp)); // 在32位的操作系统上 因为程序 最大能使用的内存空间的地址 就是2的32次方 // 指针只需要4位 就可以表示出来所有的内存空间 // 64 并且编译支持64位 8位 system("pause"); // 调用windows下系统的命令 让程序暂停执行 方便观察程序的执行结果 }
动态内存和静态内存的比较
静态内存是系统是程序编译执行后系统自动分配,由系统自动释放,静态内存是栈分配的.动态内存是堆分配的.
(1) 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static 变量。
(2) 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
(3) 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc 或new 申请任意多少的内存,程序员自己负责在何时用free 或delete 释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多.
堆和栈的区别:
1.申请方式
栈:
由系统自动分配.例如,声明一个局部变量int b; 系统自动在栈中为b开辟空间.例如当在调用涵数时,需要保存的变量,最明显的是在递归调用时,要系统自动分配一个栈的空间,后进先出的,而后又由系统释放这个空间.
堆:
需要程序员自己申请,并指明大小,在c中用malloc函数
如char* p1 = (char *)malloc(10);
但是注意p1本身是在栈中的.
2 申请后系统的响应
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时, 会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
3.申请大小的限制
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(vc编译选项中可以设置,其实就是一个STACK参数,缺省2M),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
4.申请效率的比较:
栈:由系统自动分配,速度较快。但程序员是无法控制的。
堆:由malloc/new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.
5.堆和栈中的存储内容
栈:在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。
当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。
堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。
6.内存的回收
栈上分配的内存,编译器会自动收回;堆上分配的内存,要通过free来显式地收回,否则会造成内存泄漏。
堆和栈的区别可以用如下的比喻来看出:
使用栈就像我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。
使用堆就像是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。
/*1.定义int (*pf)(int x, int y); 2.赋值 pf = add; 3.引用 pf(3,5); */ #include <stdio.h> #include <stdlib.h> int add(int x , int y){ return x+y; } main() { int (*pf) (int x, int y); //定义一个函数的指针的声明 名字叫pf 返回值 int 接受参数两个int pf = add; printf("result=%d\n", pf(3,6)); system("pause"); // 调用windows下系统的命令 让程序暂停执行 方便观察程序的执行结果 }
#include <stdio.h> #include <stdlib.h> struct Student { int age; //4 float score; // 4/ long id; //4 char sex ; //2 vc 6.0 14 }; main() { struct Student st={80,55.6f,100010 ,'F'}; struct Student* pst; pst = &st; printf("age = %d\n",st.age); printf("score = %f\n",st.score); printf("id = %ld\n",st.id); printf("sex = %c\n",st.sex); // 结构体的长度 printf("长度 = %d\n",sizeof(st)); //printf("age = %d\n", (*pst).age); printf("age = %d\n", pst->age); system("pause"); // 调用windows下系统的命令 让程序暂停执行 方便观察程序的执行结果 }
#include <stdio.h> main( ) { struct date { int year, month, day; } today; // 联合体 是定义一块相同的内存空间 存放里面的数据 union { long i; int k; char ii; } mix; // 联合体的作用就是用来表示一组数据类型 数据的数据类型为这一组中的某一种数据类型 //注意 : 联合体里面的数据内容会相互覆盖 printf("date:%d\n",sizeof(struct date)); //12 printf("mix:%d\n",sizeof(mix)); mix.ii = 'A'; printf("k=%d\n",mix.k); system("pause"); }
#include <stdio.h> typedef int haha; enum WeekDay { Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday }; // c // int main(void) { haha i = 3; printf("%d\n",i); //int day; enum WeekDay day = Sunday; printf("%d\n",day); system("pause"); return 0; }