函数
1、函数的定义
数据类型 函数名 (【数据类型 变量名 】)
int i;
在main函数中,argc表示传递多少个参数,argv 表示传递的列表 ,字符指针数组的首地址
printf("hello!\n");
printf("argc = %d!",argc);
for(i=0;i<=argc;i++)
{
puts(argv[i]);
}
return 0;
2、函数的传参
值传递:不会改变互换的参数 地址传递
void swap(int *p,int *q)
{
int tmp;
tmp = *p;
*p = *q;
*q = tmp;
}
全局变量传参
3、函数的调用
函数的嵌套调用 递归:一个函数直接或者间接的调用自身
4、函数与数组
函数和一维数组
打印数组的数据 p[]等价一个指针 ,本质还是一个指针,形参。
void print_arr(int p[],int n);
传递只是传递的一维数组的起始地址,因此要用指针偏移打印。
void print_arr(int *p,int n)
{
for(int i=0;i<=n;i++)
{
printf("%d",*(p+i));
printf("\n");
}
}
交换指针数组的顺序
void func(int *p,int n)
{
int i = 0,m;
m = (n-1)/2;
for(;i <= m;i++)
{
int temp,j;
j = n-1-i;
temp = p[i];
p[i] = p[j];
p[j] = temp;
}
}
int a[] = {1,3,5,7,9};
for(int i=0;i<sizeof(a)/sizeof(*a);i++)
{
printf("%d ",a[i]);
}
func(a,sizeof(a)/sizeof(*a));
for(int i=0;i<sizeof(a)/sizeof(*a);i++)
{
printf("%d ",a[i]);
}
函数和二维数组
打印二维数组
void print_double_arr(int *p,int n)
{
for(int i=0;i<n;i++)
{
printf("%4d ",p[i]);
}
printf("\n");
}
float average_score(int *p,int n)
{
float sum = 0;
for(int i=0;i<n;i++)
{
sum += p[i];
}
return sum/n;
}
#define M 2
#define N 5
void print_double_arr1(int (*p)[N],int m,int n);
void print_double_arr1(int p[][N],int m,int n)
{
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
printf("%4d ",*(*(p+i)+j));
printf("%4d ",p[i][j]);
printf("\n");
}
}
}
float average_score(int *p,int n)
{
float sum = 0;
for(int i=0;i<n;i++)
{
sum += p[i];
}
return sum/n;
}
打印固定的行的元素,注意什么时候传递行指针,什么时候传递列指针
void find_num(int (*p)[N],int num)
{
for(int i=0;i<N;i++)
{
printf("%4d",*(*(p+num)+i));
}
printf("\n");
}
第一种表示方式 ,将二维数组转换成为一维数组 p等价于(p+0)
void print_double_arr(int *p,int n) {
for(int i=0;i<n;i++)
{
printf("%4d ",p[i]);
}
printf("\n");
}
#define M 2
#define N 5
void print_double_arr1(int p[][N],int m,int n)
{
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
printf("%4d ",p[i][j]);
}
}
}
函数与字符数组
char* mystrcpy(char *dest,const char *src)
{
char *ret = dest;
if((dest != NULL && src != NULL))
{
while((*dest++ = *src++) != '\0')
{
}
}
return ret;
}
定义一个字符指针函数,返回值是char*类型
har* mystrncpy(char *dest,const char *src,size_t n)
{
int i;
for(i = 0;i<n&&(dest[i] = src[i]);i++);
dest[i] = '\0';
return dest;
}
char str1[] = "helloworld";
char str2[128];
mystrncpy(str2,str1,5);
puts(str2);
mystrcpy(str2,str1);
puts(str2);
5、函数与指针
指针函数 返回值 *函数名 (形参) 如:int * fun(int); 指针函数:返回的是一个指针
int * find_num1(int (*p)[N],int num)
{
if(num > M-1)
{
return NULL;
}
return *(p + num);
}
指针函数:返回的是一个指针,指针所指向的是一个入口地址
int a[2][5] = {1,3,5,7,9,2,4,6,8,10};
int num = 1;
int *res;
res = find_num1(a,num);
if(res != NULL)
{
for(int i=0;i<N;i++)
{
printf("%4d ",res[i]);
}
}
else
{
printf("can not find\n");
}
函数指针
类型 (*指针名)(形参); 如:int (*p)(int); 函数指针:函数名只是一段代码关联的入口地址
int add(int a,int b)
{
return a + b;
}
int sub(int a,int b)
{
return a - b;
}
int a = 3,b = 5;
int ret;
int (*p)(int,int);
int (*q)(int,int);
p = add;
q = sub;
ret = p(a,b);
printf("%4d ",ret);
ret = q(a,b);
printf("%4d ",ret);
函数指针数组 类型 (*数组名 【下标】)(形参) 如:int(*arrN);//数组,数组中有N个元素,这N个元素都是指向函数的指针 int (*funcp[2])(int ,int ); 函数指针数组:数组,每一项都是指针,指向函数
int a = 3,b = 5;
int ret;
int (*funcp[2])(int ,int);
funcp[0] = add;
funcp[1] = sub;
for(int i = 0;i<2;i++)
{
ret = funcp[i](a,b);
printf("%d\n",ret);
}
八、构造类型
1、结构体
(1)产生的原因和意义 存放多种不同类型变量。 (2)类型的描述 struct 结构体名字 { 数据类型 成员1;//结构体的类型名字是不占用存储空间的,因此不能直接初始化。 数据类型 成员2; … };//分号一定不能丢。 (3)嵌套定义
struct simp_st
{
int i;
char ch;
float f;
};
struct birthday_st
{
int year;
int month;
int day;
};
struct student_st
{
int id;
char name[NAMESIZE];
struct birthday_st birth;
int math;
int chinese;
};
(4)定义变量(变量、数组、指针),初始化以及成员引用 成员引用:变量名.成员名 指针->成员名 (*指针).成员名 结构体的初始化
struct simp_st a = {123,456.789,'a'};
printf("%d %f %c\n",a.i,a.f,a.ch);
struct student_st stu = {10011,"Alal",{2011,11,11},98,97};
结构体的指针传参:
struct student_st *p = &stu;
struct student_st arr[2] ={{10011,"Alal",{2011,11,11},98,97},{10012,"Jlal",{2012,12,12},91,92}};
p = &arr[0];
printf("%d %s %d-%d-%d %d %d\n",stu.id,stu.name,stu.birth.year,stu.birth.month,stu.birth.day,stu.math,stu.chinese);
for(int i=0;i<2;i++,p++)
{
printf("%d %s %d-%d-%d %d %d \n",p->id,p->name,p->birth.year,p->birth.month,p->birth.day,p->math,p->chinese);
}
(5)占用的字节大小 根据是否会字节对齐,如果字节对齐,那么占用字节数为对齐字节之后的大小,否则,是各个变量的大小的总和。比如:
struct simp_st
{
int i;
char ch;
float f;
};字节对齐占用 12个字节,不对齐占用9个字节
(6)函数传参(值,地址) 值传递:耗费地址空间 地址传递:把变量的指针传过去,消耗的是一个指针的开销。 //传参的对内存而言开销非常大,可以选择使用指针传参。
void func(struct simp_st *b){
printf("%d \n",sizeof(b));
}
struct simp_st a;
struct simp_st *p = &a;
printf("sizeof(p) = %d \n",sizeof(p));
printf("sizeof(struct) = %d \n",sizeof(a));
func(p);
2、共用体
(1)产生的原因和意义 多个成员共同存在,共用同一块内存空间根据所占内存最大的分配,只有一个成员是有效的。 (2)类型描述 union 共用体名 { 数据类型 成员名1; 数据类型 成员名2; … }; (3)嵌套定义
struct
{
int i;
char ch;
union
{
int a;
char c;
}un;
float f;
};
union
{
int a;
double d;
struct
{
int arr[10];
float f;
}un;
float f;
};
(4)定义变量(变量、数组、指针),初始化以及成员引用 成员引用:变量名.成员名 指针->成员名 (*指针).成员名 (5)占用内存大小 共用同一块内存空间根据所占内存最大的分配。 结构体和共用体嵌套得到32位的低16位和高16位的和 :巧妙
union
{
struct
{
uint16_t i;
uint16_t j;
}x;
uint32_t y;
}a;
a.y = 0x11223344;
printf("%x \n",a.x.i+a.x.j);
(6)函数传参(值传递、地址传递) 地址传参节约开销。 (7)位域
union
{
struct
{
char a:1;
char b:2;
char c:3;
}x;
int y;
}x;
3、枚举类型
enum 标识符
{
成员1:;
成员2:;
...
};
enum
{
STA_RUNNING = 1,
STA_CANCELED,
STA_OVER
};
enum day a = SAT;
printf("%d\n",a);
struct job_st job1;
switch (job1.state)
{
case STA_RUNNING:
break;
case STA_CANCELED:
break;
case STA_OVER:
break;
default:
break;
}
九、动态内存管理 auto的分配都是在栈上的,malloc可以在堆上分配。 malloc 和free最好同一个函数,或者同一个模块当中 原则:谁申请,谁释放。 malloc calloc //连续申请N块size内存的空间 realloc //重新为我分配一块内存空间,原来的空间往下继续扩展 free
int *p = NULL;
p = (int *)malloc(sizeof(int));
if(p == NULL)
{
printf("malloc() error!\n");
return 0;
}
*p = 10;
printf("%d \n",*p);
free(p);
|