嵌入式学习C语言(十五)指针函数 动态内存分配 函数指针 指针数组 指针指针
目录
一、指针函数
二、动态内存分配
malloc函数
free函数
realloc函数
calloc函数
reallocarray函数
三、函数指针
qsort函数
四、指针数组
五、指针的指针
六、两句话技巧
一、指针函数
1.返回值为指针的函数,不能返回局部变量的地址,全局变量、静态变量与传进去的指针地址均可返。
二、动态内存分配
malloc函数
1. void *malloc(size_t size);
2.size_t <==> unsigned long ,size 表示申请的空间的大小,单位字节。
3.返回值:成功返回申请到内存空间的地址;失败返回 NULL。
4.#include<stdlib.h>
5.去堆上申请一段连续的空间。返回的是一个指针,指向申请的内存空间(内存空间未初始化全是随机数)。
6.使用该函数后要判断内存空间是否申请到,申请空间申请不到会返回空指针。
7.用完要释放空间。
free函数
1. void free(void *ptr);
2.释放之前申请的堆上的空间 。
3.ptr 一定是之前申请到堆上空间的地址 。
eg 拼接字符串:先申请一个内存空间存放“Hello”字符串,再申请一个内存空间把“Hello”先放进去再把字符串“World!”拼接在后面,释放掉第一次申请的内存空间,输出拼接的字符串后释放掉第二次申请的内存空间。
int main(void){const char *s ={"Hello"};const char *t ={"World"};char * p= malloc(strlen(s) + 1); //因为隐含'\0'if(p != NULL) //说明空间申请成功{strcpy(p,s); //字符串拷入堆中。char *q = malloc(strlen(q) + strlen(t) +1); //重新申请空间,使大小够装下新的 strcpy(q,p); strcat(q,t) ; //进行拼接free(p); //释放p指向的堆空间,p变成野指针p = q; // 不让p变成野指针puts(q); //打印字符串}free(q); //释放p和q指向的堆空间return 0;}
realloc函数
1.void *realloc(void *ptr,size_t size);
2.void *ptr是原来空间的地址;size_t size是新开多大的空间;
3.把原来空间的内容拷过来并释放原来的空间,可扩大可缩小。
eg
int main(void)
{const char *s = "Hello";const char *t = "World!";char *p = malloc(strlen(s) + 1);if(p != NULL){strcpy(p, s);puts(p);p = realloc(p, strlen(p) + strlen(t) + 1);strcat(p, t);puts(p);}free(p);return 0;
}
calloc函数
1.void *calloc(size_t nmemb, size_t size);
2.申请空间numemb * size 个字节,分几块,每块几个字节。
reallocarray函数
1.一般形式:void *reallocarray(void *ptr, size_t nmemb, size_t size);
三、函数指针
1.指向函数类型的指针,指向一类函数。 int (*p) (int , int);
2.函数的函数名 函数的第一条语句 均为函数的入口地址
3.函数指针的形式要与回调函数的形式相同,参数可以只写个类型。
int add(int a,int b)
{
return a + b;
}
int sub(int a,int b)
{
return a - b;
}
int main(void)
{
int a = 10;
int b = 20;
int(*p)(int a,int b) ; // 函数指针,未赋值的野指针
p = add; // 将add函数的入口地址赋值给p
p(a,b); //间接调用函数
(*p)(a,b); //两种写法都可调用函数
return 0;
}
4.回调函数
通过函数指针在函数的参数中调用函数,将一个函数作为参数传递给另一个函数,当特定事件发生或条件满足时,接收参数的函数会调用这个传入的函数。
int pow2(int n) //返回该数的平方
{
return n * n;
}
int fn(int n) //返回该数本身
{
return n;
}
void sort(int *a,int len,int(*pfn)(int)) //第三个参数用来说明,你要比较 数的平方 还是其本身
{ // 甚至可以继续扩展,只要函数返回值为int型,且形参
int i,j; // 只有 一个int型
for(i = 0;i < len - 1;++i)
{
for(j = i + 1;j < len;++j)
{
if(pfn(a[i]) > pfn(a[j])) //调用的函数比较
{
int t = a[i];
a[i] = a[j];
a[j] = t;
}
}
}
} //这是一个选择排序函数
int main(void)
{
int a[] = {8,9,-5,1,4,3,2};
int len =sizeof(a);
sort(a,len,pow2); //根据需求按他的平方大小排序。
return 0;
}
qsort函数
1.void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
2. int (*compar)(const void *, const void *))是一个函数指针。
eg 调用qsort函数
int doublecmp(const void *p1, const void *p2)
{double *q1 = (double *)p1;double *q2 = (double *)p2;if(*q1 > *q2){return 1;}else if(*q1 == *q2){return 0;}else{return -1;}
}
int main()
{double a[] ={1,2,3,4,5,6,7,8,9,0};int len = sizeof (a) /sizeof(*a);qsort(a,sizeof(a) / sizeof(*a) , sizeof(*a),doublecmp);int i;for (i=0; i< len ; ++i){printf("lf\n",a[i]);}
}
eg 立即跳转到0x30001000地址处
void (*pfn)(void)
pfn = (void (*)(void)) 0x30001000 ;
pfn();
四、指针数组
1.int *a[10]; 定义了一个数组,有10个指针(共占80个字节)
eg1 打印字符串
void printfStrings(char *s[], int len)
{int i;for (i= 0;i < len; ++i){puts(s[i]);}
}
int main()
{char *s[3] ={"Hello","World","China"}; //s[0]存着"Hello"的地址,类推int len = sizeof(s) / sizeof (*s);printfStrings(s,len);return 0;
}
eg2 找最大值
char *maxOfStrings(char *s[], int len)
{char *max;max = s[0];int i;for(i = 1;i < len;++i){if(strcmp(max, s[i]) < 0){max = s[i];}}return max;
}
五、指针的指针
1.指向指针的指针。
void getMemory(char *p)
{p = malloc(100);
}
int main(void)
{char *s;getMemory(s);//s指针未指向malloc申请的100个字节strcpy(s, "Hello");//此行代码崩溃,s为野指针(随机数)puts(s);
}
void getMemory(char **p)// char * 是p的基类型,后边一个*是类型说明符。指向指针的指针
{p = malloc(100);
}
int main(void)
{char *s;getMemory(&s);strcpy(s, "Hello");puts(s);
}
eg1 找最大值
char *maxOfStrings(char **s, int len)
{char *max;max = s[0];int i;for(i = 1;i < len;++i){if(strcmp(max, *(s+i)) < 0){max = s[i];}}return max;
}
int main()
{char *s[] ={"Hello","World","China"};int len = sizeof (s) / sizeof (*s);puts(maxOfStrings(s,len));return 0;
}
eg 2 遍历数组
void printStrings(char **s, int len)
{int i;for(i = 0;i < len;++i){puts(*(s + i));}
}
eg3 逆序数组
void swap(char **a, char **b)
{char *t;t = *a;*a = *b;*b = t;
}void reverseStrings(char **s, int len)
{int i;for(i = 0;i < len / 2;++i){swap(s + i, s + len - i - 1);}
}
eg4 字符串选择排序
void sortStrings(char **s, int len)
{int i, j;for(i = 0;i < len - 1;++i){for(j = i + 1;j < len;++j){if(strcmp(s[i], s[j]) > 0){swap(s + i, s + j);}}}
}
eg5 字符串二分查找
int binaryFindString(char **s, int len, const char *t)
{int begin = 0;int end = len - 1;int mid;while(begin <= end){mid = (begin + end) / 2;int ret = strcmp(s[mid], t);if(ret < 0){begin = mid + 1;}else if(ret > 0){end = mid - 1;}else{return mid;}}return -1;
}
六、两句话技巧
1.二维数组作为函数参数,形参为指向数组的指针;
2.指针数组作为函数参数,形参为指向指针的指针。
eg1
void foo(int (*p)[4,int rows])
int a[3][4];
int rows = sizeof(a) / sizeof(*a);
foo(&a[0], rows);
eg 2
void bar(char **s,len)
char *s[3];
int len = sizeof(s) /sizeof(*s);
bar(&s[0], len);