---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Unity开发</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------
终于把视频全部看完了,现在进入复习阶段,今天复习了不少OC知识,但是一看下来发现问题多多,不认真准备还是很悬的,现在把之前C语言知识没有更新的内容继续更新了,要好好备考啊!
说说在论坛上总结的不起算法详解,想到牛的;然后将C语言的一些其他重点也一并总结了。
一、补齐算法详解
//注意:struct 的{}后面要加上 ”;“
#include<stdio.h>
struct A
{
int a;
double b;
char c;
} aa;
struct B
{
double b;
char c;
int a;
} bb;
struct C
{
int a;
char c;
double b;
} cc;
int main(void)
{
printf("A = %ld\n", sizeof(aa));//结果:A = 24
printf("B = %ld\n", sizeof(bb));//结果:B = 16
printf("C = %ld\n", sizeof(cc));//结果:C = 16
return 0;
}
/*
复制代码
int类型一般是占用四个字节,char类型一般占用一个字节,double类型一般占用8个字节。
1、结构体A首先给int a 分配四个字节,并且以4个字节对齐;然后给double b分配8个字节,发现
以4个字节对齐不行,就以8个字节对齐,前面只有int a ,所以int a将占用8个字节;最后为了对
齐,将给char c 也分配8给字节,所以结构体A占用了24个字节。
2、结构体B首先给double 分配8个字节,并且以8给字节对齐;然后给char c分配8给字节;最后给
int a分配空间的时候发现,前面空有7个字节空间可以放下int a,int a 就和char c一起占用8
个字节,所以结构体B占用了16个字节
3、而在GNU GCC编译器中,遵循的准则有些区别,对齐模数不是像上面所述的那样,根据最宽的基本
数据类型来定。在GCC中,对齐模数的准则是:对齐模数最大只能是4,也就是说,即使结构体中有
double类型,对齐模数还是4,所以对齐模数只能是1,2,4。而且在上述的三条中,第2条里,
offset必须是成员大小的整数倍,如果这个成员大小小于等于4则按照上述准则进行,但是如果大于4
了,则结构体每个成员相对于结构体首地址的偏移量(offset)只能按照是4的整数倍来进行判断是
否添加填充。
看如下例子:
struct T
{
char ch;
double d ;
};
那么在GCC下,sizeof(T)应该等于12个字节。
*/
二、宏定义
1.不带参数的宏
*
1.所有的预处理指令都是以#开头
2.预处理指令分3种
1>宏定义
2>条件编译
3>文件包含
3.预处理指令在代码翻译成0和1之前执行
4.预处理的位置是可以随便写的,但是有作用域
5.预处理指令的作用域:从编写指令的那一行开始,一直到文件结尾
6.宏名一般用大写或者以k开头,变量名一般用小写
*/
#include <stdio.h>
int main(int argc, const char * argv[])
{
char *name = "COUNT";//预处理指令被当做字符串处理,不会被宏定义替换
printf("%s\n",name);
#define COUNT 4 //可以将宏名写在函数当中,但是有作用域
int ages[COUNT] = {1 , 2 , 67 , 89};
for (int i = 0; i < COUNT; i++) {
printf("%d\n",ages[i]);
}
//从这里开始,COUNT这个宏就失效
#undef COUNT
int a = COUNT;
return 0;
}
2.带参数的宏
/*
int sum (int a ,int b)
{
return a + b;
}
*/
/*
1.带参数的宏定义效率比函数高
2.宏只进行参数替换,不会进行计算
*/
#include <stdio.h>
#define sum(v1, v2) ((v1) + (v2))//有编写经验的开发者,这里的形参都是要加括号的
#define pingfang(a) (a*a)//这里需要添加()的,后面是检验((a)*(a))不加()的区别
//发现,老师讲解的宏定义都是int类型,需要进行其他计算都需要进行转换运算
int main(int argc, const char * argv[])
{
// int sum(int v1 ,int v2);//这里不能有定义,
/*
//宏定义加法
int c = sum(2, 3) * sum(6, 7);
printf("%d\n",c);
*/
double c = pingfang(5+5)/pingfang(2+2);
//相当于(5+5*5+5)/(2+2*2+2)=4 35/8=4.375
//如果正确的计算,那么是((5+5)*(5+5))/((2+2)*(2+2))= 6.25
printf("%f\n",c);
/*
//普通加法
int a =10;
int b =20;
int c =sum(a, b);
printf("%c\n",c);
*/
return 0;
}
三、条件编译
#include <stdio.h>
//只要写了#if ,在最后面必须加上#endif,原因,细看老师讲解视频
#define A 5
#define XM xiaoli
int main(int argc, const char * argv[])
{
#ifndef A
//#ifdef A
//#if !define(A)
printf("哈哈\n");
#endif
/*
int a = 10;
if (a == 10) {
printf("a的值是10\n");
}else if(a == 5){
printf("a的值是5\n");
}else{
printf("a是其他值\n");
}*/
//条件编译的优势:在编译之前就执行,只编译满足条件的句子,条件不满足的句子,就不在编译过程编译,直接省略,这比条件函数执行效率更高
/*
#if (A == 10)
printf("a的值是10\n");
#elif(A == 5)
printf("a的值是5\n");
#else
printf("a是其他值\n");
#endif
*/
#if (XM == xiaoli)//这里需要别注意,这里的字符串不需要加“”,因为XM宏定义替换过来之后是没有“”的
printf("他是小李\n");
#elif (XM ==xiaoming)
printf("他是小明\n");
#else
printf("他是其他人\n");
#endif
return 0;
}
四、typedef类型
1.基本使用
/*
1.作用:给已经存在的类型起一个新的名称
2.使用场合:
1>基本数据类型
2>指针
3>结构体
4>枚举
5>指向函数的指针
*/
#include <stdio.h>
//定义基本数据类型
typedef int MyInt;
typedef MyInt MyInt2;
//给指针类型char *起一个新的类型名称String
typedef char * String;
/*定义结构体类型
struct Student
{
int age
};
typedef struct Student MyStu;
*/
typedef struct Student
{
int age;
} MyStu;
/*
typedef struct
{
int age;
} MyStu;
*/
//定义枚举类型
typedef enum {
Man,
Woman
} MySex;
//定义指向函数的指针类型
typedef int (*MyPoint)(int ,int);
int minus(int a,int b)
{
return a - b;
}
int sum(int a ,int b)
{
return a + b;
}
//定义指向结构体的指针
/*
struct Person
{
int age;
};
typedef struct Person * PersonPoint;
*/
typedef struct Person
{
int age;
} * PersonPoint;
int main(int argc, const char * argv[])
{
//定义结构体变量
struct Person p = {20};
PersonPoint p2 = &p;
//struct Person *p2 = &p;
// int (*p)(int ,int) = sum;
//
// int (*p2)(int ,int) = minus;
//
// p(10 ,11);
// MySex s = Man;
// enum Sex s = Man;
// enum Sex s2 = Woman;
// struct Student stu3
// MyStu stu = {20};
// MyStu stu2 = {21};
return 0;
}
//定义指向数组类型
void test2()
{
String name = "jack";
printf("%s\n",name);
}
void test()
{
int a;
MyInt i = 10;
MyInt2 c = 20;
MyInt b1 ,b2;
printf("c is %d\n",c);
}
2.使用注意事项
#include <stdio.h>
//#define Integer int
//typedef int Integer;
//tepedef unsigned long int MyInt;
#define String2 char *
typedef char * String;
int main(int argc, const char * argv[])
{
/*解释第一句等于第二句和第三句,为了解释#define和typedef做基础
int a ,b;
int a;
int b;
*/
//这里s1、s2都是char *指针
String s1,s2;
/*
String s1;
String s2;
*/
s1 = "jack";
s2 = "rose";
//s3才是char *指针,s4是char类型
String2 s3 ,s4;
/*
char *s3,s4;
char *s3;
char s4;
*/
return 0;
}
五、static和extern对函数的作用
1.基本使用
/*
外部函数:定义的函数能被本文件和其他文件访问
1>默认情况下所有函数都是外部函数
2>不允许有同名的外部函数
内部函数:定义的函数只能被本文件访问,其他文件不能访问
1>允许不同文件中有同名的内部函数
static对函数的作用
1>定义一个内部函数
2>声明一个外部函数
extern对函数的作用:
1>完整地定义一个外部函数
2>完整地声明一个外部函数
(extern可以省略,默认情况下声明和定义的函数都是外部函数)
*/
//声明一个test函数
//完整地声明一个外部函数
//extern可以省略
//extern void test()
void test();
//void test2();
#include <stdio.h>
int main(int argc, const char * argv[])
{
test();
//test2();
return 0;
}
//void test()
//{
//
//}
static void test2()
{
}
#include <stdio.h>
//声明一个内部函数,必须要注意提前声明
static void test2();
//完整地定义一个外部函数
/*
extern void test()
{
printf("调用了test函数\n");
}
*/
//默认情况下,所有的函数都是外部函数,所以可以省略extern
void test()
{
printf("调用了test函数\n");
test2();
}
//定义一个内部函数
static void test2()
{
printf("调用了test2函数\n");
}
2.全局变量
/*
全局变量分2种:
外部变量:定义的变量能被本文件和其他文件访问
1>默认情况下,所有的全局变量都是外部变量
2>不同文件中得同名外部变量,都代表着同一变量
内部变量:定义的变量只能被本文件访问,不能被其他文件访问
1>不同文件中得同名内部变量,互不影响
static对变量的作用:
定义一个内部变量
extern对变量的作用:
声明一个外部变量
static对函数的作用:
定义和声明一个内部函数
extern对函数的作用:定义和声明一个外部函数(可以省略)
*/
#include <stdio.h>
void test();
int a;
extern int a;
//定义一个内部变量
static int b;
int main(int argc, const char * argv[])
{
//b = 10;
//test();
int a;
a = 10;
/*
a = 10;
test();
printf("a的值是%d\n",a);
*/
return 0;
}
int a;
3.static对局部变量的作用
#include <stdio.h>
/*
static修饰局部变量的使用场合
1.如果某个函数的调用频率特别高
2.这个函数内部的某个变量值是固定不变的
*/
void test()
{
static double pi = 3.14;
double zc = 2 * pi *10;
int a = 0;
a++;
printf("a的值是%d ",a);
/*
static修饰局部变量:
1>延长局部变量的生命周期:程序结束的时候,局部变量才会被销毁
2>并没有改变局部变量的作用域
3>所有的test函数都共享着一个变量b
*/
//这里使用了局部变量,那么这里的b只会在内存中分配一次,并且直到程序结束时才会被销毁,根据下面调用函数情况,这里的显示结果是b = 1, b = 2 , b = 3;
static int b = 0;
b++;
printf("b的值是%d\n",b);
}
int main(int argc, const char * argv[])
{
//下面显示结果
test();//
test();
test();
return 0;
}
六、递归
//计算一个数的n次方
/*
递归的2个条件:
1.函数自己调用自己
2.必须有个明确的返回值
*/
#include <stdio.h>
int pow2(int b,int n);
int main(int argc, const char * argv[])
{
int c = pow2(3,2);
printf("%d\n",c);
return 0;
}
/*
pow2(b , 0) == 1
pow2(b , 1) == b == pow2(b ,0) * b
pow2(b , 2) == b*b == pow2(b ,1) * b
pow2(b , 3) == b*b*b == pow2(b ,2) * b
1> n为0,结果肯定是1
2> n>0,pow2(b ,n) == pow2(b , n-1) *b
*/
int pow2(int b,int n)
{
if (n <= 0) return 1;
return pow2(b , n -1) *b;
}
/*
int pow2(int b,int n)
{
//用来保存计算结果
int result = 1;
// result *= b;
// result *= b;
// result *= b;
// result *= b;
// ....
// n次
for (int i = 0; i<n ; i++) {
result *= b;
}
return result;
}*/
C语言知识点也不少,总结的时候要做总结笔记,特别是自己不懂和中重要的地方。
---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Unity开发</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------