苏嵌实训——day6(上)

简介: 苏嵌实训——day6(上)

一 函数指针


函数指针:本质是一个指针,指向一个函数

我们定义的函数名其实就是一个指针,保存当前函数代码区的首地址

函数指针学习的目的就是想解决能不能定义一个指针,可以像函数名一样对当前函数进行调用

函数指针定义的格式:

返回值类型(*变量名)(参数);

函数数值真的作用:将一个函数作为参数传递给另一个函数是需要定义成函数指针,也称之为回调函数


#include <stdio.h>
typedef unsigned char uchar;   //用uchar表示 unsigned char
typedef int (*T)(int,int);   //声明T为函数指针类型
void f1()
{
  printf("hello world!\n");
}
int f2(int x,int y)
{
  printf("this is f2\n");
  return 0;
}
int main(int argc, const char *argv[])
{
  void (*p1)();  //定义函数指针
  p1 = f1;//不能写成p1 = f1();   ---->调用f1函数,将返回值赋值给p1
  p1();
   // p1 = f2;   //类型不兼容
   int (*p2)(int,int);
   p2 = f2;
   p2(1,2);
   T p3;  //等价于int(*p3)(int,int)
   p3 = f2;
   p3(1,2);
  return 0;
}


二 回调函数


#include <stdio.h>
int less(int x,int y)
{
  return (x < y) ? 1 : 0;
}
int greater(int x,int y)
{
  return (x > y) ? 1 : 0;
}
void Sort(int a[],int length,int (*p)(int,int))
{
  int i,j;
  for(i = 0 ; i < length - 1;i++)
  {
  for(j = 0 ; j < length - 1 - i;j++)
  {
    if(p(a[j],a[j+1]))
    {
#if 0
    int t = a[j];
    a[j] = a[j+1];
    a[j+1] = t;
#endif
    a[j] = a[j] + a[j + 1];
    a[j + 1] = a[j] - a[j + 1];
    a[j] = a[j] - a[j + 1];
    }
  }
  }
}
void Print(int a[],int length)
{
  int i;
  for(i = 0 ; i < length;i++)
  {
  printf("%d ",a[i]);
  }
  putchar(10);
}
int main(int argc, const char *argv[])
{
  int a[10] = {0};
  printf("请输入10个数字:\n");
  int i;
  int length = sizeof(a)/sizeof(a[0]);
  for(i = 0 ; i < length;i++)
  {
  scanf("%d",&a[i]);
  }
  Sort(a,length,less);
  Print(a,length);
  return 0;
}


练习:编写函数,定义一个无符号4字节的整数,然后获取每一个字节的内容,然后返回相加之和


要求:这个整数需要传参,返回每一个字节之和

458963212 —>‭0001 1011 0101 1011 0011 1001 0000 1100‬

0000 1100‬ —>12

0011 1001 —> 57

0101 1011 —>91

0001 1011 —> 27

12+57+91+27 = 187


#include <stdio.h>
int GetByteSum(unsigned int num)
{
  int sum = 0;
#if 0
  //将每8位拿出来
  int byte1,byte2,byte3,byte4;
  byte1 = num & 0xff;
  byte2 = (num >> 8) & 0xff;
  byte3 = (num >> 16) & 0xff;
  byte4 = (num >> 24) & 0xff;
  sum = byte1 + byte2 + byte3 + byte4;
#endif
  unsigned char *p = (unsigned char)&num;
  int i;
  for(i = 0 ; i < 4; i++)
  {
  sum += *p;
  p++;
  }
  p = NULL;
  return sum;
}
int main(int argc, const char *argv[])
{
  unsigned int num = 458963212;
  int n = GetByteSum(num);
  printf("n = %d\n",n);
  return 0;
}


面试题:


define和typedef的区别?


1.#define是一个预处理指令,在预处理阶段进行字符串的简单替换,并不参与到编译阶段,typedef是类型的重定义,在编译的时候进行过类型的重定义

2.当使用#define和typedef定义多个指针的时候,define定义的是第一个指针,后面全是变量,而typedef定义的全是指

3.define一般用于表示常量,还有函数的替换工作,typedef用于类型重定义


#include <stdio.h>
#include <stdlib.h>
// 方法1:({})
// 方法2:do{}while(0)
int min;
#define MAX(a,b) ({int max;if(a > b)max=a;else max=b;max;})  //({})里面可以有多条语句,最后一句就是宏的返回值
#define MIN(a,b) do{if(a < b) min = a;else min = b;}while(0)
#define PRINT_MSG(msg) do{printf("%s\n",msg);return -1;}while(0)
#define S(n) #n   //#代表字符串化
int main(int argc, const char *argv[])
{
  int *p  = NULL;
  int hello = 100;
  printf("max = %d\n",MAX(100,200));
  MIN(100,200);
  printf("min = %d\n",min);
  p = (int *)malloc(4);
  if(p == NULL)
  {
  PRINT_MSG("malloc failed!\n");
  }
  printf("%s\n",S(10));  //字符串化
  return 0;
}


三 存储类型


auto:

register:定义变量在寄存器上,运行速率快,但是芯片的寄存器的个数有限制,不能无限使用

寄存器变量不能取地址

extern: 使用的变量或者文件在其它文件中定义

static:

1.限定作用域:(修饰的变量或者函数只能在本文件中使用)

2.延长生命周期

volatile:保证数据每次都从内存中取值,而不从缓存中取数据,防止编译器对代码进行优化

1.多线程访问同一个变量的时候

2.使用C语言操作硬件地址的时候


#include <stdio.h>
int a = 100;
void fun()
{
  static int i = 0; 
  printf("i = %d\n",i++);
  printf("a = %d\n",a);
}
int main(int argc, const char *argv[])
{
  int a = 200;
  printf("a = %d\n",a);
  {
  int a = 300;
  printf("a = %d\n",a);
  }
  printf("i = %d\n",i);
  fun();
  fun();
  fun();
  return 0;
}


四 内存管理


栈区:局部变量,正在调用的函数,形参都在栈

栈区由于在释放时不会清0,所以在定义变量的时候不初始化,他们都是随机值,

栈区空间由系统自动申请,自动释放

堆区:使用malloc分配的内存都在堆区,手动申请,手动释放

静态区|.bss:使用static修饰的未初始化的变量和全局的未初始化的变量在.bss段

|----------------------------

|.data:使用static修饰的已初始化的变量和全局的已初始化的变量在.data段

|----------------------------

|.text:代码段,文本段

|----------------------------

|.ro: 只读数据段

|const int a;

|char *p = “helloworld”;


#include <stdio.h>
int a; //.bss段
static int w = 4; //.data
int b = 1234;   //.data
const int g = 789; //.ro
void func(void)
{
  const int y = 1234; //.ro
  int *p = &y;  //栈区
}
int main(int argc, const char *argv[])
{
  char ch; //.stack
  char ch1 = 'a';  //.stack
  char *p = "aaaa"; //P .stack  "aaaa":.ro
  return 0;
}


思考题1


#include <stdio.h>
int main(int argc, const char *argv[])
{
  char *p = NULL;
  char *tmp = "helloworld";
  p = (tmp + 4);
  //p[-1] = ? p[-5] = ?
  printf("p[-1] = %c,p[-5] = %c\n",p[-1],p[-5]);
  return 0;
}


思考题2


#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
  char *data = "12345678";
  short *tmp = NULL;
  char p[6] = {0};
  tmp = (short *)&p[2];
  *tmp = atoi(&data[4]);
  printf("*tmp = %d\n",*tmp);//“5678”,atoi一直到'\0'结束
  //p[0],p[1],p[2],p[3],p[4],p[5]?
  int i = 0 ; 
  for(i = 0 ; i < 5;i++)
  {
  printf("p[%d] = %#x\n",i,p[i]);
  }
  return 0;
}

jsetc@linux:~/jsetc/208/day6$ ./8-思考题2

*tmp = 5678

p[0] = 0

p[1] = 0

p[2] = 0x2e

p[3] = 0x16

p[4] = 0


五 结构体


结构体是一个构造类型,结构体的成员在内存上是连续的,

但是结构体的成员的类型可以是不相同的。

结构体的关键词用struct来标注。


格式:
struct 类型名{
    成员1;
    成员2;
    。。。
};
(1)结构体使用struct来标识
(2)struct后面跟的是结构体的类型名,而非变量名
(3)结构体的成员是被{}所包括着
(4){}后面要加;
(5)结构体的成员可以不尽相同
(6)结构体成员之间用分号隔开
(7)定义结构体的时候不能赋值
(8)在结构体里面不能写函数,因为函数占用的字节不固定,但是可以写函数指针
(9)结构体访问成员的方式 “变量.成员”
(10) 结构体指针访问成员的方式“变量->成员”


5.1 结构体的使用


5.1.1 结构体的定义和赋值


#include <stdio.h>
struct person{
  char name[32];
  char sex;
  int age;
  int high;
  float weight;
};
int main(int argc, const char *argv[])
{
  struct person p1;
  strcpy(p1.name,"张三");
  p1.sex = 'm';
  p1.age = 18;
  p1.high = 189;
  p1.weight = 80;
  struct person *p2 = NULL;
  p2 = (struct person *)malloc(sizeof(*p2));
  if(p2 == NULL)
  {
  printf("malloc failure");
  }
  strcpy(p2->name,"张三");
  p2->sex = 'm';
  p2->age = 18;
  p2->high = 189;
  p2->weight = 80;
  return 0;
}


5.1.2 定义结构体同时赋值


#include <stdio.h>
struct person{
  char name[32];
  char sex;
  int age;
  int high;
  float weight;
};
int main(int argc, const char *argv[])
{
  struct person p1 = {"zhangsan",'m',20,186,80}; //给所有成员初始化
  struct person p2 = {             //选择成员初始化
  .name = "zhangsan",
  .weight = 80
  };
  return 0;
}


5.1.3 结构体数组


struct person p1[3]; //这个就是结构体数组,数组中有三个strcut person


5.2 结构体定义的方式


5.2.1 无名结构体


struct{
  char name[32];
  int age;
  float weight;  
}变量1,变量2;
struct 变量1;-----》这个是错误的写法
typedef struct{
    char name[32];
    int age;
    float weight;
}student_t;  //类型名
student_t 变量1,变量2;


注意:结构体可以整体赋值,数组在定义后不允许整体赋值


相关文章
|
网络协议 安全 网络安全
苏嵌实训——day18
苏嵌实训——day18
114 0
苏嵌实训——day18
|
消息中间件 Linux
苏嵌实训——day16(下)
苏嵌实训——day16(下)
苏嵌实训——day16(下)
|
Ubuntu API 数据库
苏嵌实训——day19
苏嵌实训——day19
113 0
苏嵌实训——day19
|
网络协议 数据安全/隐私保护 网络架构
苏嵌实训——day17(上)
苏嵌实训——day17(上)
苏嵌实训——day17(上)
|
消息中间件 存储 Linux
苏嵌实训——day16(上)
苏嵌实训——day16(上)
苏嵌实训——day16(上)
|
存储 Linux 程序员
苏嵌实训——day13(上)
苏嵌实训——day13(上)
115 0
苏嵌实训——day13(上)
|
存储
苏嵌实训——day11(下)
苏嵌实训——day11(下)
106 0
苏嵌实训——day11(下)
|
存储 Ubuntu 固态存储
苏嵌实训——day1
苏嵌实训——day1
146 0
苏嵌实训——day1