复习C语言中的5中基本类型,以及各个类型占用了多少个字节:
#include <stdio.h> int main(void) { printf("int=%d\n", sizeof(short int)); printf("int=%d\n", sizeof(int)); printf("int=%d\n", sizeof(long int)); printf("char=%d\n", sizeof(char)); printf("float=%d\n", sizeof(float)); printf("float=%d\n", sizeof(double)); return 0; }
复习数组, 常量指针, 变量指针, 常量指针的指向地址是不能改变的, 但是变量指针的指向地址是可以改变的:
#include <stdio.h> int main() { int i; //a为常量指针 int a[] = {4,5,6,7}; int len = sizeof(a)/sizeof(a[0]); //循环数组,并获取数组中的值; for(i=0 ;i<len; i++) { printf("%d\n",a[i]); }; for(i=0 ;i<len; i++) { printf("%d\n",*(a+i)); }; //定义一个指针, 指向数组, 此时的指针pa为变量指针 int* pa; pa = a; for(i=0 ;i<len; i++) { printf("%d\n", pa[i]); } for(i=0 ;i<len; i++) { printf("%d\n", *(pa+i)); } //让指针 pa++ ,输出数组的指针 printf("%d\n", *(pa++)); //让数组 a++ ,输出结果, 会报错, 因为a是常量指针, 无法改变的; //printf("%d\n", a++); return 0; }
通过指针修改数组, 和直接修改数组的方式:
#include <stdio.h> int main() { int ar[] = {1,2,3,4}; int* p; p = ar; //*p = 0; //*p指向p的第一个元素; p[0] = 0; //这个上一行的代码效果一模一样; //*(p+1) = 0; //这一行和上面一行效果也是一样的 p[1] = 0; printf("%d\n",ar[0]); printf("%d\n",ar[1]); return 0; }
在调用函数的时候,可以传值:
#include <stdio.h> void Exchg1(int x, int y) { int tmp; tmp=x; x=y; y=tmp; printf("x=%d,y=%d\n",x,y); } int main() { int a=4,b=6; Exchg1 (a,b) ; printf("a=%d,b=%d\n",a,b); return 0; }
也可以传指针, 指针的话就变成后面的回调函数了:
#include <stdio.h> void Exchg2(int *px, int *py) { int tmp=*px; *px=*py; *py=tmp; printf("*px=%d,*py=%d\n",*px,*py); } int main() { int a=4; int b=6; Exchg2( &a,&b); printf("a=%d,b=%d\n", a, b); return 0; }
指针是c中的一大玩点, 但是指针终究是指针 , 如果参数为一个数组, 指针是无法获取到指针对应的值的长度的, 所以要把数组给一个函数, 都要把数组的长度作为参数传递?这个有待考证
#include <stdio.h> void run(int *p, int *p1) { printf("p 的长度是%d\n", (int)sizeof(*p)); } int main() { int a[] = {1,2,3,4,5,6,7,8}; run(a, b); printf("a 的长度是 : %d\n", (int)sizeof(a)); return 0; } //输出: //p 的长度是 : 4 //a 的长度是 : 32
#include <stdio.h> //float average( int*p 一样 ,int len) { float average( int a[] ,int len) { float val; int sum = 0; //printf("%d\n", a); for(int i=0; a[i]!=9999; i++) { printf("%d\n", a[i]); }; a[0] = 9; return val; } int main() { int x[] = {1,2,3,4,5,6,7,8,9,10,9999}; float av; //c语言中的指针不带有长度信息, 必须把长度作为参数; av = average(x, sizeof(x)/4); printf("%d\n", x[0]); return 0; }
定义数组的变量,即为这个数组的首地址, 把数组作为参数的时候, 被调用的函数中的参数为这个数字的引用:
#include <stdio.h> void average( int a[] ) { a[0] = 9; } int main() { int x[] = {1,2,3,4,5,6,7,8,9,10,9999}; average(x); //x的第一个值是 : 9 printf("x的第一个值是 : %d", x[0]); return 0; }
接受参数的时候, 可以定义一个数组作为形参数:
#include <stdio.h> void average( int* p ) { p[0] = 9; } int main() { int x[] = {1,2,3,4,5,6,7,8,9,10,9999}; average(x); //输出:x的第一个值是 : 9 printf("x的第一个值是 : %d", x[0]); return 0; }
一个字符或者数字只是一个变量, 把以上两种类型作为参数的时候, 实际上传递的只是一个原始值的复制品:
#include <stdio.h> void test( int p ) { p = 9; } int main() { int x = 0; test(x); //输出:x的第一个值是 : 0 printf("x的值是 : %d", x); return 0; }
也可以把字符或者数字作为一个指针,传递给函数, 函数定义的时候接收, 在调用的函数中修改指针, 对应的变量会发生改变:
#include <stdio.h> void test( int* p ) { *p = 9; } int main() { int x = 0; test(&x); //输出:x的第一个值是 : 9 printf("x的值是 : %d", x); return 0; }
搞笑的数组和指针:
#include <stdio.h> int main() { int a[10]; int *p; int i; for(p = a; p<a+10; p++){ printf("p is %d \n", p); } return 0; }
循环输入学生的分数,冒泡排序以后重新输出分数, malloc(Byte):
#include <stdlib.h> #include <stdio.h> void sort( int *s , int len) { int i = 0, j = 0; //冒泡排序 for(i=0; i<len; i++) { for(j=i; j<len; j++) { if( s+j>s+i ) { int temp = 0; temp = *(s+i); *(s+i) = *(s+j); *(s+j) = temp; } } } } int main() { int *a , j , n; scanf("%d\n",&n); a = (int *)malloc(10); for(j=0; j<n; j++) { scanf("%d",a+j); } printf("puts trings\n"); sort(a, n); for(j=0; j<n; j++) { printf("%d\n",*(a+j)); } free(a); return 0; }
实现一个命令行的投票功能, 输入li或者zhang, 投的票数会自动增加 :
#include <stdio.h> #include <string.h> struct per { char name[20]; int count; }leader[2] = {{"li",0},{"zhang",0}}; int main() { int i , j; int p; char name[20]; printf("enter ‘li‘ or ‘zhang‘ : \n"); for(i = 0; i<6; i++) { scanf("%s\n", name); for(j = 0; j<2; j++) { if(strcmp(leader[j].name, name) == 0) { leader[j].count = leader[j].count+1; }; } } for(i = 0; i<2 ; i++) { printf("user %s, count is %d\n", leader[i].name, leader[i].count); } return 0; }
字符串的复制需要strcpy, 原始类型的复制可以使用左值直接赋值:
#include <stdio.h> #include <string.h> struct st{ char name[10]; int age; }s2; int main() { char c[] = "abcd"; char b[4]; strcpy(b,c); printf("string is : %s\n",b); struct st s1 = {"nono",28}; s2.age = s1.age; printf("s2 age is : %d\n", s2.age); strcpy(s2.name, s1.name); printf("s2 name is : %s\n", s2.name); return 0; }
利用结构体实现简易的用户查询系统, 包含用户的添加以及查询:
#include <stdio.h> #include <string.h> #include <stdlib.h> struct user{ int id; char name[20]; char descript[20]; }s[20];//预置20个用户 int count = 0; void find() { printf("please to enter user id:\n"); int id = 0, i; scanf("%d", &id); for(i=0 ;i <count; i++) { if(s[i].id == id) { printf("user id is %d\n user name is %s \nuser desciprtion %s\n", s[i].id, s[i].name, s[i].descript); } } } void all() { int i = 0; for(i=0 ; i<count; i++) { printf("user name : %d\n", s[i].id ); printf("user name : %s\n", s[i].name ); printf("user desciprtion : %s\n", s[i].descript ); } } void add() { char name[20]; char descript[20]; printf("input user name :\n"); scanf("%s",name); printf("input user desciprtion:\n"); scanf("%s",descript); user s1; //= { count , *name, *descript}; s1.id = count; strcpy(s1.name, name); strcpy(s1.descript, descript); s[count] = s1; count++; } int main() { //用户的输入: char ipt[10]; //循环获取用户的输入 printf("%d\n", (int)(sizeof(s)/sizeof(s[0]))); while(1) { printf("\n\n\n\n输入查询:\n "); printf("查询所有输入:all \n 增加用户输入:add\n 查询详细输入:find\n"); //获取用的输入 scanf("%s", ipt); printf("%s", ipt); //查看所有的用户 if(strcmp(ipt, "all")==0) { all(); } //增加一个用户 if(strcmp(ipt,"add")==0) { add(); } //根据用户ID, 返回查询用户消息 if(strcmp(ipt,"find")==0) { find(); } } return 0; }
内存管理(MM), 通过malloc申请内存,以及使用free返还内存:
#include <stdio.h> #include <stdlib.h> int main() { char *p; p = (char *)malloc(8); int i; for(i=0; i<8; i++) { p[i] = i; } for(i=0; i<8; i++) { printf("address is %p;content is %c\n",&p[i],p[i]); } free(p); return 0; }
#include <stdio.h> #include <stdlib.h> int main() { char *p; p = (char *)malloc(8); int i; for(i=0; i<8; i++) { p[i] = i; } for(i=0; i<8; i++) { printf("address is %p;content is %c\n",&p[i],p[i]); } free(p); return 0; }
买车的实现:
#include <stdio.h> #include <string.h> #include <stdlib.h> struct car{ char maker[10]; int deposit; }; struct people{ char name[10]; int deposit; car *c; }; void buy(people *p) { car *c = (car *)malloc(sizeof(car)); strcpy(c->maker, "bench"); c->deposit = 10; p->deposit -= c->deposit; p->c = c;; } void discard(people *p) { free(p->c); p->c = NULL; } int main() { people p = {"nono",100,NULL}; printf("people name is : %s\n", p.name); printf("people deposit is : %d\n", p.deposit); buy(&p); printf("after buy it , people deposit is : %d\n", p.deposit); printf("%s has a car, the car name is %s\n",p.name, p.c->maker); discard(&p); return 0; }
链表的使用, 链表和数组的区别以及各自不同的使用场景,有头节点和无头节点的区别和区别:
链表是动态生成的, 可控性比数组好非常多, 数组的长度是固定的,但是链表可以无限延长, 对于链表的操作也比较灵活, 可以往链表的中间插入数据, 但是数组的插入是非常繁琐的;
有头链表保障了链表起码有一个开始, 对于数据的操作更灵活, 无头链表必须保证,头部有一个数据, 否者无法做后续操作:
#include <stdio.h> #include <string.h> #include <stdlib.h> /* *网吧用户管理系统 */ struct User { //用户名 char name[10]; //用户密码 char pass[10]; //用户金额 int deposit; User* next; }; //察看所有 void showAll(User *user) { User *curr = user; while(curr->next) { curr = curr->next; printf("user : %s\ndeposit:%d\n",curr->name,curr->deposit); } } //添加用户 void add(User *user) { //局部创建的变量, 在离开该函数的作用域后, 会被自动清空; char name[10]; char pass[10]; int deposit = 0; printf("please enter user name :\n"); scanf("%s",name); printf("please enter user pass :\n"); scanf("%s",pass); printf("please enter user deposit :\n"); scanf("%d",&deposit); //必须使用MM申请空间, 然后再往user下添加数据 User *u = (User*)malloc(sizeof(User)); u->deposit = deposit; strcpy(u->name, name); strcpy(u->pass, pass); u->next = NULL; //循环,直到,user没有下一个数据; while(user->next){ user = user->next; printf("find next\n"); }; user->next = u; //printf("next is :%p\n",user->next); } void find(User *user) { char name[10]; printf("enter user name to find : \n"); scanf("%s", name); User *curr = user; while(curr->next) { if( strcmp(curr->next->name, name) == 0 ) { printf("user is %s\ndeposit is %d\n", curr->next->name, curr->next->deposit); return ; } curr = curr->next; } } //删除用户 void remove(User *user) { char name[10]; printf("enter user name to rmove : \n"); //数组的话只要传name,因为name本来就是一个地址 //字符和数字要加&因为,他们本身是数据,要根据地址改数据; scanf("%s", name); User* curr = user->next; while( curr->next ) { if( strcmp(curr->next->name, name) == 0 ) { User *now = curr->next; curr->next = now->next; free(now); printf("removed\n"); return ; } user = user->next; } } int main() { User user = {"","",0,NULL}; char cmdline[10]; while(1) { //输出查看,添加,删除命令 printf("查看所有:all\n添加用户:add\n删除用户:remove\n查找用户信息:find\n"); scanf("%s",cmdline); printf("you are enter : %s\n", cmdline); //如果是察看 if(strcmp("all",cmdline) == 0) { showAll(&user); }; //如果是添加 if(strcmp("add",cmdline)==0) { add(&user); } //如果是删除 if(strcmp("remove",cmdline)==0) { remove(&user); } //如果是删除 if(strcmp("find",cmdline)==0) { find(&user); } } return 0; }
引用相关, 定义一个引用的时候, 必须初始化, 但是定义指针不要强制初始化, 定义完毕引用以后,无法解绑,被强制绑定, 无法重新赋值 :
#include <stdio.h> struct stu { char name[16]; int age; }; int main() { //refference引用是强化版的指针 int a = 100; //定义一个引用的时候, 必须初始化, 但是定义指针不要强制初始化 //定义完毕引用以后,无法解绑,被强制绑定, 无法重新赋值 int&b = a; printf("b = %d, address : %p\n", b,&b); printf("a = %d, address : %p", a,&a); stu s = {"nono",10}; stu& s1 = s; printf("把s1的age改成100"); s1.age = 100; printf("s的age is %d\n", s.age); return 0; }
引用可以作为返回值:
#include <stdio.h> int b = 1000; int& test() { //如果我把b定义在test函数内部, 会报错, 因为函数执行完毕以后, 内部的所有变量都会被销毁; int& a = b; return a; } int main() { int& a = test(); printf("The a is %d\n", a); return 0; }
可以把引用作为返回值, 但是这种写法不太好阅读, 不方便阅读理解:
#include <stdio.h> int number = 0; int& test() { return number; } int main() { test() = 4; printf("%d\n", number); return 0; }
done
参考: