【嵌入式Linux笔记】01-函数、指针

2019-07-13 00:59发布

本文内容: 函数--》函数定义、子函数、函数作用域、主函数传参、递归函数 指针--》指针定义、指针当数组、函数传参指针、指针字符串操作、指针和数组、指针和函数、指针和const、野指针
  • 函数
1.函数的定义:”黑匣子“ 。通过一些特定的调用,去实现我们需要的功能
        好处:代码模块化,查找错误方便
        用法:主函数main()  子函数fun()
        
2.子函数编写组成
  int add(int a,int b)
  {
    printf("%d ",a+b);
  }
  2.1  类型    int    void      char
      返回值:整数    无返回值  字符
           return
           
  2.2  add    函数名
       名字怎么取都行,但是要符合编程规范
       
  2.3 {...}
            函数功能具体
            
  2.4 (int a,int b) 函数的形参
       调用时候,传一个实参进去(类型匹配) /* 1、通过输入数字,产生调用子函数,做一个计算器 + - x / please input two number 12 23 please input computer (+ - * /) + 秘籍:防止输入的时候产生多余的回车符,使用下%*c */ #include int add(int a,int b)//做加法 { printf("%d ",a+b); } int sub(int a,int b)//做减法 { printf("%d ",a-b); } int mul(int a,int b)//做乘法 { printf("%d ",a*b); } int div(int a,int b)//做除法 { printf("%d ",a/b); } int main() { int num1,num2; char bolo; printf("请输入两个要计算的数: "); scanf("%d",&num1); scanf("%d",&num2); printf("请输入您要计算的方式(+ - * /): "); scanf("%*c%c",&bolo); switch(bolo) { case '+': add(num1,num2); break; case '-': sub(num1,num2); break; case '*': mul(num1,num2); break; case '/': div(num1,num2); break; default: printf("违规操作! "); break; } return 0; } 3.函数作用域
       局部
          一般来说在{}里面
   
       全局
          它在所有函数的外部定义,它的作用域是在整个.c里面的函数       
          如果全局变量和局部变量重名,那么全局变量的作用域将被抵消
   
       extern 声明外部的变量
          如果外部变量或者函数前面加上了static,就算你加个extern你没用
           情况一:修饰函数,你想使用别人的.c
           情况二:修饰全局变量
       
       static  声明内部的变量, 别人没法使用的
            声明全局变量,限制了全局变量的使用位置仅限当前.c  
   
4.主函数传参
    在函数运行时候,在./main后面可以添加参数
    4.1 int main()
    4.2 int main(void)
    4.3 int main (int argc,char *argv[])
    4.4 int main (int argc,char **argv)
    4.5 int main (int argc,const char **argv)    
    
    1.argc====》传入参数的个数(main函数执行的时候参数的数量)
    2.argv====》传入参数的值
            gec@ubuntu:/mnt/hgfs/linux$ ./test alse return float
            4 ./test
            4 alse
            4 return
        作用:argc   对比输入参数是否有误
              argv   对密码和对比用户 5.递归函数
      解决某些核心问题:比如有一个问题,后面的步骤和前面的步骤存在相同的地方
       阶乘 5!    = 5*4*3*2*1
      在递归的思想里面 
         自己调用自己,将n传参到函数里面,直到n=1时候    
  /* 2、编写一个程序, 此程序要求输入天数, 然后将该值转换为星期数和天数。 例如输入 18, 则要求输出:18 days are 2 weeks, 4days */ #include void weekday(int date) { int week; int day; week=date/7; day=date%7; printf("%d days are %d weeks, %d days ",date,week,day); } int main(void) { int n; printf("请输入天数: "); scanf("%d",&n); weekday(n); return 0; } /* 3、编写一个程序, 用户输入某个大写字母, 产生一个金字塔图案,例如用户输入字母 E, 则产生如下图案: A ABA ABCBA ABCDCBA */ #include int code(char a) { int i; int j; int s; if( a>=65 && a<=90)//ASCII码中65-90都是大写字母 { for(i=65;i<=a;i++) //行高 { for(j=i;j<=a;j++)//空格 { printf(" "); } int z=65;//字母初始 for(s=65;s<=2*(i-65)+65;s++)//字母 { if(s /* 4、编写一个程序, 该程序读取输入直到遇到#字符, 然后报告读取的空格数目、 读取的换行符数目 以及读取的所有其他字符数目。 */ #include int main() { int x=0;//空格 int y=0;//回车换行 int z=0;//其他 char code; printf("please input a char: "); while(1) { scanf("%c",&code); if(code == '#') { break; } else if(code == ' ') { x++; } else if(code == ' ') { y++; } else { z++; } } printf("报告读取的空格数目 %d ",x); printf("报告读取的换行数目 %d ",y); printf("报告读取的其他数目 %d ",z); }
  • 指针
C语言里面存放大量的相同类型的数据,无非就两种方法:
     一:数组
     二:指针
     
指针的定义: 存放地址的变量
      定义方式:int *a;和int* a;这两个是相同的
          这是一个int *类型的指针a
          
指针和数组关系:数组名是首地址
    int a[10];
    int *p;
    p=a;
    printf("%p ",a);
    printf("%p ",&a[0]);
    printf("%p ",p);
地址:
    0xbfb08ad4
    0xbfb08ad4
    0xbfb08ad4 数组的访问:
    第一种:通过下标直接去访问
    
    第二种:通过指针去访问 指针的运算
解引用     *
      直接在指针的前面加上*
      int *p; <==>int* p;
       指针:p  ----地址      
        值 :*p ----具体的值
      作用:获取指针的值
      
取地址
            &
        对象(变量的值)
      作用:获取一个变量的地址   指针的大小
  对于指针来说。在32位机器上,大小都是一样的,都是4字节
                在64位机器上,大小都是一样的,都是8字节    定义int*  char* 表示所指的类型 指针的加法
 加法:
  int *p;
  printf("%p ",p);
  p=p+1;          //指针+1就是加上一个int类型
  printf("%p ",p);
  
  0xb777eff4
  0xb777eff8      4字节   char *q;
  printf("%p ",q);
  q=q+1;         //指针+1就是加上一个char类型
  printf("%p ",q);   0xb76ccff4
  0xb76ccff5      1字节 总结: 指针的加法:每次增加一个对应的类型
       指针的减法:每次减少一个对应的类型 指针的操作
要注意的问题:
   1.
       int str[10];
       int *p=str;  //获取的首元素的地址
       int *q=&str; //获取的是数组的地址
   2.*号的优先级比+号要高的,
     *p+1      先解引用p获取数值,然后数值+1
     *(p+1)    先对指针加1,然后解引用获取数值
     
指针的应用1:将指针当做数组来用
   char str[10]="helloworld";
   char *p;
   int i;
   p=str;
   for(i=0;i<10;i++)
   {
       printf("%c",p[i]);//指针带下标
       printf("%c",*(p+i));
       printf("%c",str[i]);
   }
   printf(" "); 指针的应用2:函数传参指针
通过指针去修改变量的值
      
    值传递:参数是普通的变量,传递的仅仅只是值,和原来的变量是没有关系
    地址传递:参数是指针,可以通过指针修改值。 void *指针----》通用型指针   可以和其他的任何类型去匹配
        
指针的应用3:字符串操作
字符串
    由一系列的字符组成 字符串的头文件:#include 比较常用的6个字符串:
             1.strlen  计算字符串的长度
             2.strcpy  复制一个字符串到另一个字符串
             3.strcmp  比较两个字符串是否一样
             4.strcat  拼接两个字符串
             5.strstr  查找子串
             6.strtok  分解字符串
    
    查看资料:看看剩下的函数怎么使用
             1.man手册
             2.C语言标准函数库
             3.http://www.baidu.com             
        
    strstr
      头文件:#include       函数模型:char *strstr(const char *haystack, const char *needle);
      函数作用:在一个字符串里面寻找子串
         参数:const char *haystack     母串
               const char *needle       子串 
                
    strtok
       头文件:#include        函数模型:char *strtok(char *str, const char *delim);
       函数作用:用来将一个字符串做拆分的
           参数:char *str           要拆分的对象
                 const char *delim   拆分的标志 /* 1.使用指针操作,编写一个my_strcpy,将“hello”,拷贝到一个数组里面 */ #include #include // 位置 字符串 void my_strcpy(char *a,char *b) { int i; for(i=0;i /* 2.通过指针操作:实现一个my_strcmp (strcmp()效果) ./main 123456 密码输入正确 打印hello 输入错误 程序结束 */ #include #include int my_strcmp(char *s1,char *s2) { int i; for(i=0;i /* 3.将字符串“2018-08-07”中的年月日取出来 */ #include #include int main(int argc,char **argv) { char str[]="2018-08-07"; char *delim="-";//分割标志 char *p; printf("%s ",strtok(str,delim)); while(p=strtok(NULL,delim)) { printf("%s ",p); } return 0; } 指针的应用4:指针和数组
 数组指针:-----》指向数组的指针
 数组指针定义:
        int (*p)[10];
        int buf[10];
          
          //p=buf;//指向数组的首元素   no
          p=&buf;//指针指向整个数组
        
 指针数组-----》数组里面存的是指针
 指针数组定义:
        int *p[10];<===>int* p[10];
    常见例子            
   int main(int argc,char **argv)
        char* *argv <===>char **argv
        char* argv[]<===>char *argv[]
        
   究竟如何去区分数组指针还是指针数组
     看这个指针有没有加括号
     
总结:int  buf[10];
     1.buf    首元素的地址 等价于 &buf[0]
     2.&buf   等价于一个数组指针
   
指针的应用5:指针和函数
1.数组作为函数的参数
      实际上相当于一个指针,传递的地址
      //int add(int buf1[5],int buf2[5],int buf[5])写法1
       int add(int *buf1,int *buf2,int *buf)写法2 2.函数指针和指针函数
  函数指针的写法
      int (*p)(int a,int b);
      int (*p)(int *a,int *b);       int add(int a,int b)
        {
           return a+b;
        }
      p=add;//p函数指针指向add函数
      写法一:(*p)(12,23);
      写法二:p(12,23);
      
  指针函数的写法
      int *p(int,int);
      int *p(int a,int b);
      int *p(int *a,int *b);
      
      int add(int a,int b)
      {
           return a+b;
      }
    
      返回值:是一个指针
      
分析:
     int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
     分析第三个参数:void *(*start_routine) (void *)
           第一步:用指针*p去替换*start_routine
           第二步:void *(*p)(void *)
                   void  (*p)(void *)   
                     函数指针               
     
     void (*signal(int sig,void (*func)(int)))(int);
     void ()(int);
      分析:拆一个:void (*func)(int)     函数指针
                    *signal(int sig,int ) 指针函数 返回值:是一个指针
                    void  (*p)(int);      函数指针
                    
    用变量 a 给出下面的定义
    a) 一个整型数        
int a;
    b) 一个指向整型数的指针int *a;
    c) 一个指向指针的的指针, 它指向的指针是指向一个整型int * *a;===int **a;
    d) 一个有 10 个整型数的数组int a[10];
    e) 一个有 10 个指针的数组, 该指针是指向一个整型数的int *a[10];
    f) 一个指向有 10 个整型数数组的指针int (*a)[10];
    g) 一个指向函数的指针, 该函数有一个整型参数并返回一个整型数int (*a)(int);
    h) 一个有 10 个指针的数组, 该指针指向一个函数, 该函数有一个整型参数并返回一个整型数int (*a[10])(int); 指针用法6:cons
  const是一个C语言的关键字,它限定一个变量不允许被改变
  情况一:修饰指针,限定活动范围
        写法一:
            const int  *p;
          表示p可以访问指向地址中的内容,但是指针p不能修改指向的地址内容
        写法二:
            int const  *p;
          表示p可以访问指向地址中的内容,但是指针p不能修改指向的地址内容
        写法三:
            int *const p=&a;
          表示p可以修改它指向的地址的内容,但是指针p不能够在指向其他的地址
  情况二:修饰变量
        1.const int a=10;
        2.int const a=10;
        3.const int a;     no 常量只能在一开始就初始
           a=10;
        4.int const a;     no
           a=10; 指针用法7:野指针
  你定义了指针,但是你没有指明内存地址,你就直接往里面写数据,----》段错误
  讨论代码中所有的语句在内存中是如何存放?
  栈内存:局部变量,空间是有限的,一般的操作系统8M左右,故不要在代码当中定义太大的局部变量(防止栈溢出)
  堆内存:堆是一个自由内存,堆的大小不设限,它的大小由系统的物理内存决定
    解决方案:
        使用函数malloc calloc  realloc 给指针分配一个堆空间,让它不再是野指针。
            #include
               void *malloc(size_t size);
                   参数:size_t size 你打算申请的空间字节数
                   返回值:你成功申请的那块内存的首地址
                   
               void free(void *ptr);释放空间
                   参数:void *ptr 释放你不需要的空间的首地址
                   
               void *calloc(size_t nmemb, size_t size);
                   按块来分配内存空间
                   参数:size_t nmemb  你打算申请多少块内存
                         size_t size  每一块内存空间的大小
               
               void *realloc(void *ptr, size_t size);
                    给指针重新分配内存空间
                    参数:void *ptr  原来那块空间的首地址
                         size_t size 你想要重新申请多大的空间
                        
    区别:malloc  不会帮你将申请的空间清零
          calloc  帮助你清零
          realloc 重新分配的内存空间的首地址和原来的有可能一样,也有可能不一样