一、函数和指针
1. 函数指针(指向函数的指针)。 例如: int (*pf)( );
例:
#include <stdio.h>
void print()
{
printf("Hello\n");
}
int add(int x, int y)
{
return (x+y);
}
int main()
{
int m;
void (*p)();
p = print;
p();
int (*q)(int, int);
q = add;
m = q(1, 2);
printf("%d", m);
return 0;
}
其中 p = print; 和 q = add; 是将地址赋值给指针,函数名就是一个地址;
2. 指针函数(指针里保存函数)。例如:int *p( );
例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *Init()
{
char *tmp = (char *)malloc(sizeof(char)*10);
return tmp;
}
int main()
{
char *str;
str = Init();
strcpy(str, "hello");
printf("%s", str);
return 0;
}
其中 str = Init();是将函数赋给指针函数 ,等号两边等价。
3.练习(1)int * ( * ( * fp ) ( int ) ) [10] ;
* fp // fp是一个指针
* ( * fp ) ( int ) // 指针指向一个有int型参数的函数,函数的返回值是一个指针
int * ( * ( * fp ) ( int ) ) [10] // 指针指向一个有10个元素的数组,数组中的每个元素都是int型的指针
(2)int * ( * ( * array [5] )( ) ) ( ) ;
* array [5] // array是一个有五个元素的数组,每个元素都是一个指针
* ( * array [5] )( ) // 每个指针指向一个函数,函数的返回类型是一个指针
int * ( * ( * array [5] )( ) ) ( ) ; // 每个指针指向一个函数,函数的返回类型是一个int型指针
二、数组和指针
1. 指向二维数组的指针的表示方式
表示形式 | 含义 | 地址值 |
&a | 指向二维数组的指针 | 1000 |
a | 二维数组名,指向一维数组a[0],即第0行首地址 | 1000 |
a[0] , *(a+0) , *a | 第0行第0列元素地址 | 1000 |
a+1 , &a[1] | 第1行首地址 | 1006 |
a[1] , *(a+1) | 第1行第0列元素地址 | 1006 |
a[1]+2 , *(a+1)+2 , &a[1][2] | 第1行第2列元素地址 | 1010 |
*(a[1]+2) , *(*(a+1)+2) , a[1][2] | 第1行第2列元素的值 | 元素值为11 |
&a[i]或a+i指向行,而a[i]或*(a+i)指向列
例:
#include <stdio.h>
int main()
{
int a[3][4] = {{1, 2, 3, 4}, {3, 4, 5, 6}, {5, 6, 7, 8}};
int i;
int (*p)[4] = a, *q = a[0];
for(i = 0; i < 3; i++)
{
if(i == 0)
{
(*p)[i + i/2] = *q + 1;
}
else
{
p++, ++q;
}
}
for(i = 0; i < 3; i++)
{
printf("%d,", a[i][i]);
}
printf("\n");
printf("%d,%d\n", *((int *)p), *q);
return 0;
}
其中int ( * p ) [ 4 ] = a ;p是指针,指向一个有4个元素的数组。因为a + 1是加一行(4个元素,16字节),所以p + 1也要加16个字节,数组中元素个数取4。
2. 二维数组指针
#include <stdio.h>
int main()
{
int i, j;
int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
int (*p)[4] = a;
for(i = 0; i < 3; i++)
{
for(j = 0; j < 4; j++)
{
printf("%d ", a[i][j]);
printf("%d ", *(*(p + i) + j));
printf("%d ", p[i][j]);
printf("%d ", (*(p + i))[j]);
}
printf("\n");
}
return 0;
}
其中 a[ i ] [ j ] === * ( * ( p + i) + j ) === ( * ( p + i ) ) [ j ] === p[ i ] [ j ]
三、指向指针的指针
例1:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void MemoryInit(char **str)
{
*str = (char *)malloc(sizeof(char) * 64);
}
int main()
{
char *ptr = NULL;
MemoryInit(&ptr);
strcpy(ptr, "Helloworld");
printf("%s\n", ptr);
return 0;
}
函数传地址时 &ptr = **str; 其中ptr是指针也是地址,&ptr是地址的地址,**str也是地址的地址
&ptr 是函数调用要传递地址(参见两数交换的程序)
例2:
#include <stdio.h>
int main()
{
char *name[] = {"Follow", "BASIC", "Great", "For", "Computer"};
char **p;
int i;
for(i = 0; i < 5; i++)
{
p = name + i;
printf("%s\n", *p);
}
return 0;
}
定义时 name[ ]是数组名也是一个地址,*name[ ]是地址的地址,+1加到下一个元素
**p也是地址的地址,所以p = name + i成立
输出时 *p是取值, 就少了一层地址,还剩一层地址,而数组本身就是一个地址,就相当于取数组的值
四、命令行参数(main函数的函数)
1. main (int argc,char *argv[])
argc(第一个形参)必须是整型变量,表示参数的个数
argv( 第二个形参)必须是指向字符串的指针数组,表示具体的参数
2. 使用命令行参数编写字符串排序
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void sort(char *a[], int length)
{
int i, j;
char *tmp;
for (i = 1; i <= length - 1; i++)
{
for (j = 1; j <= length - i - 1; j++)
{
//if (a[j + 1] < a[j])
if (strcmp(a[j + 1], a[j]) > 0)
{
tmp = a[j + 1];
a[j + 1] = a[j];
a[j] = tmp;
}
}
}
}
void print(char *a[], int length)
{
int i;
for (i = 1; i < length; i++)
{
printf("%s ", a[i]);
}
printf("\n");
}
int main(int argc, char *argv[])
{
int i, j, tmp;
int length = argc;
sort(argv, length);
print(argv, length);
return 0;
}
运行时 ./sort.c aaa bbb ccc ddd (输入需要比较的字符串)