黑马程序员 《ios零基础教程》 --补齐算法、宏定义、typedef、递归 2014-4-20总结

---------------------- <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>、期待与您交流! ----------------------

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值