类型字节 :
实用宏:
#define MAX(a,b) (((a)>(b)) ? (a):(b))
String字符串:
输入:char str[],gets(str) 输出:%s
遇到”烫”经验问题是:字符串越界,或者多输出,一般重置输出范围和末尾加’\0’即可。
extern用法:
extern表明变量或者函数是定义在其他其他文件中的。例如:extern int a;显式的说明了a的存储空间是在程序的其他地方分配的,在文件中其他位置或者其他文件中寻找a这个变量。
用法
一个c文件需要调用另一个c文件里的变量或者函数,而不能从.h文件中调用变量。
extern int a = 5与int a = 5意义是一样的,都是定义。而extern int a;是声明。但会产生一条警告。
对于函数而言,和引用变量是一样的,如果需要调用其他.c文件中的函数,在文件中的函数声明前加extern即可,不加extern而直接声明函数也可以,因为声明全局函数默认前面带有extern。
如果不想让其他.c文件引用本文件中的变量,加上static即可。
建议最优用法
例如:a.c文件中定义int a = 5和一个函数,在a.h里写extern int a;,如果要在其他文件里调用a这个变量和函数,直接#include即可
extern和include的区别
include相当于把include .h文件直接带入到本源文件里,比如在b.c文件里include “a.h”,就相当于把a.h文件里所有定义的变量和函数全部拷贝了一份放入了b.c里,一个项目里,一个.h文件可能会被多个.c源文件包含,这样编译的时候就会报重复定义的错误。而且尽量不要在.h里定义变量,这是一个不好的习惯
C语言中,用"->“和用”."的区别
首先 a->b 的含义是 (*a).b,(*a).b 和 a->b 是等价的
一般情况下用“.”,只需要声明一个结构体。格式是,结构体类型名+结构体名。然后用结构体名加“.”加域名就可以引用域 了。因为自动分配了结构体的内存。如同 int a;一样。
而用“->”,则要声明一个结构体的指针,还要手动开辟一个该结构体的内存,然后把返回的指针给声明的结构体指针,才能用“->”正确引用。否则内存中只分配了指针的内存,没有分配结构体的内存,导致想要的结构体实际上是不存在。这时候用“->”引用自然出错了,因为没有结构体,自然没有结构体的域了。
符号解释:
&:按位与
|:按位或
关于内存分配malloc、calloc、realloc
1.从静态存储区域分配.
内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在.例如全局变量、static变量.
2.在栈上创建
在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放.栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限.
3.从堆上分配,亦称动态内存分配.
程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存.动态内存的生存期由用户决定,使用非常灵活,但问题也最多.
(1) malloc()
在内存的动态存储区中分配一块长度为size字节的连续区域,参数size为需要内存空间的长度,返回该区域的首地址.
(2) calloc()
与malloc相似,参数sizeOfElement为申请地址的单位元素长度,numElements为元素个数,即在内存中申请numElements*sizeOfElement字节大小的连续地址空间.
(3) realloc()
给一个已经分配了地址的指针重新分配空间,参数ptr为原有的空间地址,newsize是重新申请的地址长度.
区别:
函数malloc不能初始化所分配的内存空间,而函数calloc能.如果由malloc()函数分配的内存空间原来没有被使用过,则其中的每一位可能都是0;反之, 如果这部分内存曾经被分配过,则其中可能遗留有各种各样的数据.也就是说,使用malloc()函数的程序开始时(内存空间还没有被重新分配)能正常进行,但经过一段时间(内存空间还已经被重新分配)可能会出现问题.
函数calloc() 会将所分配的内存空间中的每一位都初始化为零,也就是说,如果你是为字符类型或整数类型的元素分配内存,那么这些元素将保证会被初始化为0;如果你是为指针类型的元素分配内存,那么这些元素通常会被初始化为空指针;如果你为实型数据分配内存,则这些元素会被初始化为浮点型的零.
函数malloc向系统申请分配指定size个字节的内存空间.返回类型是 void类型.void表示未确定类型的指针.C,C++规定,void* 类型可以强制转换为任何其它类型的指针.
realloc可以对给定的指针所指的空间进行扩大或者缩小,无论是扩张或是缩小,原有内存的中内容将保持不变.当然,对于缩小,则被缩小的那一部分的内容会丢失**.realloc并不保证调整后的内存空间和原来的内存空间保持同一内存地址**.相反,realloc返回的指针很可能指向一个新的地址.
realloc是从堆上分配内存的.当扩大一块内存空间时,realloc()试图直接从堆上现存的数据后面的那些字节中获得附加的字节,如果能够满足,自然天下太平;如果数据后面的字节不够,问题就出来了,那么就使用堆上第一个有足够大小的自由块,现存的数据然后就被拷贝至新的位置,而老块则放回到堆上.这句话传递的一个重要的信息就是数据可能被移动.
Qsort普通数组使用模板:
int cmp(const void *a, const void *b)
{
return *(int *)a - *(int *)b;
}
Qsort多级结构使用模板:
int cmp(struct medalInfo *a,struct medalInfo *b) {
medalInfo *c1 = (medalInfo*)b;
medalInfo *c2 = (medalInfo*)a;
if(c1->gold_medal > c2->gold_medal)
return 1;
if(c1->gold_medal < c2->gold_medal)
return 0;
if(c1->silver_medal > c2->silver_medal)
return 1;
if(c1->silver_medal < c2->silver_medal)
return 0;
if(c1->brone_medal > c2->brone_medal)
return 1;
if(c1->brone_medal < c2->brone_medal)
return 0;
需要#include
qsort(实际结构体countryInfo, count, sizeof(**结构体名字medalInfo**), cmp);
PS:注意从大到小和从小到大的逻辑!!!
(int *)a是表示把a强制转换成一个int型的指针。
如果以前a是char型,编译器会认为a指向的那一个字节的内存单元是a里面的东西
把a转换成int型,编译器会认为a指向的连续四个字节里的东西都是a里面的。
*(int *)a就是取a指向的内容的意思,跟*a的那个*作用一样
快排:
void sort(int *a, int left, int right)
{
if(left >= right)/*如果左边索引大于或者等于右边的索引就代表已经整理完成一个组了*/
{
return ;
}
int i = left;
int j = right;
int key = a[left];
while(i < j) /*控制在当组内寻找一遍*/
{
while(i < j && key <= a[j])
/*而寻找结束的条件就是,1,找到一个小于或者大于key的数(大于或小于取决于你想升
序还是降序)2,没有符合条件1的,并且i与j的大小没有反转*/
{
j--;/*向前寻找*/
}
a[i] = a[j];
/*找到一个这样的数后就把它赋给前面的被拿走的i的值(如果第一次循环且key是
a[left],那么就是给key)*/
while(i < j && key >= a[i])
/*这是i在当组内向前寻找,同上,不过注意与key的大小关系停止循环和上面相反,
因为排序思想是把数往两边扔,所以左右两边的数大小与key的关系相反*/
{
i++;
}
a[j] = a[i];
}
a[i] = key;/*当在当组内找完一遍以后就把中间数key回归*/
sort(a, left, i - 1);/*最后用同样的方式对分出来的左边的小组进行同上的做法*/
sort(a, i + 1, right);/*用同样的方式对分出来的右边的小组进行同上的做法*/
/*当然最后可能会出现很多分左右,直到每一组的i = j 为止*/
}
输出闪退:system(“pause”);
数组的输出:
输出的输出需要新建一个指向原数组的指针才能正常输出
方法一:
medalInfo *p;
p = countryInfo;
for (int i = 0; i < count; i++) {
printf("%s\n", p[i].name);
}
方法二:
int display_name(medal_info_t* medal_info, int count){
int i = 0;
for(i = 0; i < count; i++){
printf("%s\n", medal_info[i].name);
}
return 0;
}
结构体赋值:
typedef struct {
char name[25];
int gold_medal;
int silver_medal;
int brone_medal;
}medalInfo;
(scanf("%s%d%d%d",
countryInfo[j].name,//因为这是数组可以不用取址符
&countryInfo[j].gold_medal,
&countryInfo[j].silver_medal,
&countryInfo[j].brone_medal)!=EOF);