Linux系统及C高级学习日报day5

一、shell中函数的语法格式

        function    函数名()

        {

                函数体

        }

        注意:

        1>shell中的函数使用function进行修饰,function可写可不写,建议写;

        2>shell中的函数没有返回类型,如果接受shell函数的返回值呢?

                2.1>shell 中定义的变量默认就是全局的变量,可以直接使用

                2.2>如果shell中的变量使用local 定义局部的变量

                        可以使用return 进行返回,return返回只能返回0-255之间的数。

                        接受返回值使用$?,$?可以获取上一条指令的执行结果。

                2.3>在函数中可以使用echo命令输出函数的返回值,接收函数的返回值时,使用命令置换符``,获取函数的返回结果。

        3>函数的形参

                shell的函数不需要形参列表,但是可以给函数传递实参。

                在shell函数内如何获取给shell函数传递的实参呢?使用位置变量

                       $0----->执行shell 脚本文件的名字

                       $1----->第一个实参

                       $2----->第二个实参

                        .......

                        ${n}---> 第n个实参 (n>10,需要加{ } )

                        $*或¥@----> 获取所有的实参

        4>shell 中的函数依然要向C中的函数遵循先声明,后使用的原则

                但是shell 中的函数都是声明和定义写到一起的,及shell 中的函数的定义应该写到函数调用的前边。

        5>shell中的函数的调用

                函数名        实参列表

例:将打印⼆进制的代码封装为函数

#!/bin/bash 

    # 函数的封装: 功能 参数 返回值 (函数的三要素)
    # 调用库函数: 研究函数的功能 参数 返回值
    function  convert() {

        local ret=''
        local num=$1
        # seq  用来输出序列化  seq 开始 间隔 结束 默认是间隔1
        for p in `seq 1 32` 
        do 
            if (($num & 0x80000000))
            then
                ret="${ret}1"
            else
                ret="${ret}0"
            fi
            num=$(($num<<1))
        done
        echo $ret
    }


    read -p "请输入一个无符号的整数 > " num
    value=`convert $num`
    echo "0b${value}"

二、C高级------宏定义

1.常量宏

#define  DEBUG   3.14

#define  M              3

#define  N               4

#define  ADD  ((M)+(N))

                1>宏定义在预处理阶段进行替换

                2>宏定义中有复杂的表达式,多多使用()

                3>进行宏定义时,默认不允许出现换行,如果使用换行,必须在每行的结尾加一个换行符\

2.使用宏函数,最后一个表达式的结果作为宏函数的返回值

                #define MAX(a,b) ({a>b?a:b;})

                1>宏函数在底层封装时经常使用。

#include  MAX(a,b)        ({  (a)  >  (b)  ?  (a)  :  (b) ;})

                #include  MIN(a,b)  ({int ret;\

                                                   if(a>b)\

                                                           ret = b;\

                                                    else ret =a;\

                                                     ret; })

3.宏定义和do { }while(0);结合使用   ——>在底层的封装经常使用,宏定义多条语句时

 #include <stdio.h>

    // 宏定义和do{}while(0)结合
    #define  print()   do{ \ 
                printf("input error"); \
                printf("please try again input > ") \
                } while(0)

 4.宏定义中使用#----->将宏定义的参数转换成一个字符串

#include <stdio.h>
    // 将n转换成一个字符串  #n等价于"n"
    #define  str(n)  #n 
    #define  string  "helloworld"
    int main(int argc, const char *argv[])
    {
        // 等价于 printf("helloworld\n")
        printf(str(helloworld\n));
        // 等价于printf("%s\n", "zhoukai")
        printf("%s\n", str(zhoukai));

        printf("%s\n", string);
        return 0;
    }

 5.宏定义中使用两个##------>实现宏定义中的参数的拼接

#include <stdio.h>
    // 实现宏中两个参数的拼接 
    #define name(a,b)  a##b

    #define uint32_t   unsigned int 
    #define uint16_t   unsigned short 
     
    // 使用宏定义编写一个模板函数 
    #define MAX(T)  T max_##T(T a, T b) { \
                    return (a>b?a:b); \
                    }
    // 调用宏函数,定义两个函数
    MAX(double)
    MAX(int)

    #define  max(T)  max_##T

    int main(int argc, const char *argv[])
    {
        name(uint, 32_t)  a = 100;
        name(uint, 16_t)  b = 200;

        printf("max double = %f\n" , max_double(3.14, 5.67));
        printf("max int = %d\n" , max_int(3, 1));
        printf("max double = %f\n" , max(double)(3.14, 5.67));
        printf("max int = %d\n" , max(int)(3, 1));

        return 0;
    }

6.宏定义的预定义

       

//   当行注释 
	/**/  多行注释, 注不可以嵌套
	#if 0/1  #else  #endif    多行注释 
	
	5.1> #ifndef
	#define  宏名    // 宏定义
	#ifndef   宏名    ===》 宏不可以进行逻辑运算
		// 如果宏没有定义,则这段代码有效
	#else  
		// 如果宏定义了,则这段代码有效
	#endif 
	5.2> #ifdef 
	#ifdef   宏名     ===》 宏不可以进行逻辑运算
		// 如果宏定义了,则这段代码有效
	#else  
		// 如果宏没有定义,则这段代码有效
	#endif 
	
	5.3> defined()
	#if defined(宏) 
		// 如果宏定义了,则这段代码有效
	#else 
		// 如果宏没有定义,则这段代码有效
	#endif 
	
	#if !defined(宏) 
		// 如果宏没有定义,则这段代码有效	
	#else 
		// 如果宏定义了,则这段代码有效
	#endif 
	
	#if defined(宏1)  || defined(宏2) ....
		// 只要有一个宏定义了,则这段代码有效
	#else 
		// 两个宏都没有定义,则这段代码有效
	#endif 
	#if defined(宏1)  && defined(宏2)  ....
		// 两个宏都有定义,则这段代码有效		
	#else 
		// 只要有一个宏没有定义了,则这段代码有效
	#endif 
	
	#if !defined(宏1)  || defined(宏2) ....
		// 第一个宏没有定义或者第二个宏定义了则这段代码有效
	#else 
		// 上边无效的时候,下边就有效
	#endif 
	
	#include <stdio.h>
    #define DEBUG
    #define DEBUG2
    int main(int argc, const char *argv[])
    {
    #ifndef  DEBUG 
        printf("这是一段调试代码\n");
    #else 
        printf("这不是一个调试代码\n");
    #endif

    #ifdef  DEBUG2 
        printf("这是一条调试代码\n");
    #else 
        printf("这不是一个调试代码\n");
    #endif 


    #if defined(DEBUG) || defined(DEBUG2)
        printf("两个中一定有一个定义了\n");
    #else 
        printf("两个中一定都没有一个定义了\n");
    #endif

        return 0;
    }

 三、多文件的编程

        将具有相同功能的代码放到一个.c文件,不同功能的代码放到不同.c文件中,多文件变量目的是为了工程的方便管理,阅读代码方便。

一般是一个.c文件对应一个.h文件。

.c文件中一般用于函数定义,变量的定义,

.h文件中一般书写函数声明,变量的声明。

tree 命令  sudo apt-get install tree
modules  --> 一个工程一个文件夹
├── include   ---> 放所有的头文件
├── main.c    ---> 主函数
└── src      ----> 放所有的源文件
头文件的重复包含机制 
#ifndef __***_H__
#define __***_H__

#endif // __***_H__

 四、动态内存分配------>  malloc/free

1.malloc函数的分析------>man  malloc

#include <stdlib.h>

    void *malloc(size_t size);
    /*
    	函数的功能: 在堆区动态的分配内存空间
    	函数的参数: 
    		@ size  : 在堆区分配多少字节的空间,单位为字节
    	函数的返回值: void *
    		@ 成功: 返回分配堆区空间的首地址
    		@ 失败: 返回NULL
    */

2.free函数的分析-----> man  free

#include <stdlib.h>

    void free(void *ptr);
    /*
    	函数的功能: 手动释放堆区的空间 
    	函数的参数: 
    		@ ptr : 释放堆区空间的首地址 
    	函数的返回值:
    		@ 无
    */

3.总结:
1.在程序中可以动态指定本次分配内存的⼤⼩
2.malloc分配的内存在堆区
3.malloc分配的内存是连续的,可以通过数组的格式访问内存中的数据
    p = (int *)malloc(sizeof(int)*10); 在堆区分配40个字节的空间,并且是连续的。
4.malloc申请的内存需要free释放,如果在⼀个⼀直运⾏的程序中,
    反复调⽤malloc,但是没有调⽤free就会导致"内存泄漏"。
    如果malloc申请的内存没有调⽤free,
    但是程序执⾏结束了,内存会被操作系统释放掉。
5.malloc申请的内存在释放的时候,⼀定使⽤的是从⾸地开始的内存。 
    free函数调⽤之后⼀定要将指针执向NULL,
    否则在使⽤这个指针的时候就是在使⽤"野指针"
    
    
    如果释放堆区的空间没有执向NULL,则这个指针已让可以使用,
    并且编译不会报错,当时使用了非法的内存空间,别人再次malloc时
    这块空间又可能会被重新分配,执行也不会报错,但是程序的运行结果为止。
    如果释放堆区的空间没有指向NULL,就会出现野指针。
    
    如果释放堆区的空间,并且释放之后将指针指向NULL,
    此时这个指针依然可以使用,编译器不会报错,
    但是指向时会报段错误(核心已转储).

 4.

1> 分配空间 
        2> 使用分配空间 
        3> 释放空间
        4> 让指针指向NULL,防止野指针的出现
        在实际的开发中杠修改bug大多数都是野指针,段错误相关问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值