目录
一、指针函数
二、动态内存分配
malloc函数
free函数
realloc函数
calloc函数
reallocarray函数
三、函数指针
qsort函数
四、指针数组
五、指针的指针
六、两句话技巧
1.返回值为指针的函数,不能返回局部变量的地址,全局变量、静态变量与传进去的指针地址均可返。
1. void *malloc(size_t size);
2.size_t <==> unsigned long ,size 表示申请的空间的大小,单位字节。
3.返回值:成功返回申请到内存空间的地址;失败返回 NULL。
4.#include
5.去堆上申请一段连续的空间。返回的是一个指针,指向申请的内存空间(内存空间未初始化全是随机数)。
6.使用该函数后要判断内存空间是否申请到,申请空间申请不到会返回空指针。
7.用完要释放空间。
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;
}
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;
}
1.void *calloc(size_t nmemb, size_t size);
2.申请空间numemb * size 个字节,分几块,每块几个字节。
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;
}
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);