int a[10];
int *p;
p = &a[0];//或者 p = a;
*(p+i); //-->a[i];
*p++; <==> *(p+i);
p在变化,输入结束后p指向了数组最后; <==> p没有变化,输入结束也在数组开头;
*p++;如何运算:
1)复制一个p指向对象的副本;
2)让指针p指向后偏移一格;
3)返回副本p的值。
int a[][4];
int a[3][]; //错误
可以省略第一个,但是不可以省略第二个。
为什么二维数组和一维数组在内存中的存储方式一样
因此可以像操作一维数组一样操作二维数组:
二维数组是通过不同的基准点和不同的偏移量-->使用一位数组的方法是一个基准点不同的偏移量。
选好基准点数组下边也可以是负数
------------------------------------------------
int a[3][4];
int (*p)[4];//哪一个都不能少,确定 p+1 这加1会移动多少字节 变相的二级指针
p = a;
如何通过p访问a[i][j]
p+i --> 指针指向第i行
*(p+i) --> 将第i行内容取出来,此时指针指向第i行的首地址
*(p+i)+j --> 在第二步的基础上,获取a[i][j]元素的地址
*(*(p+i)+j) --> 在第三步的基础上,取出a[i][j]元素的值
char str[]="HelloWorld";
char *p;
p = str;
char str[]="HelloWorld";==>char *str="HelloWorld";
如果这么写就会出现:段错误-->不是编译错误,是运行错误,问题是当前程序操作了非法内存
char str[]="HelloWorld";
将“HelloWorld”存入数组str内;
char *str="HelloWorld";
在内存的某块区域存储着“HelloWorld”,指针str指向了该内存
字符串是常量,字符数组是存储和处理字符串的变量==>在不影响语义的情况下可以混为一谈
PS:流 和 文件 --> FILE* 流指针
1.野指针与空指针
int a;
int *p;
p = &a;
野指针:定义指针未指向有效对象-->没有办法在编译的时候检测出来(危害还特别大)
空指针:没有指向任何一块内存的指针
int *p = NULL;//可以用来防范野指针
2.返回值是指针的函数(指针函数)
#include
int *ser(int score[][4],int n) //指针函数
{
return *(score+n); //返回第n行的首地址
}
int main()
{
int score[3][4] = {
99,88,77,66,
88,77,66,55,
77,66,55,44,
};
int n;
int *a;
scanf("%d",&n);
if(n>=1 && n<=3) //判断输入是否正确
{
n--; //二维数组是从第 0 行开始的:输入1-->变为 0
a = ser(score,n); //将第n行的首地址返回给指针 a
for(n = 0; n < 4; n++) //循环输出这一行的每一个数
{
printf("%3d",a[n]);
}
printf("\n");
}
else //输入错误的行,报错
printf("erro\n");
return 0;
}
#include
char *getmermory() //指针函数
{
char *p="Hello World";
return p;
}
int main()
{
char *str = getmermory();
printf("str is %s\n",str);
return 0;
}
3.指向函数的指针
函数的类型是由函数返回值与函数参数列表共同决定
返回值类型 ( * 指针变量名) ([形参列表]);
int sub(int x,int y)
{
return x-y;
}
int (*p)(int,int); //定义函数指针
p = sub;
sub(x,y);<==>p(x,y);
发明函数指针的目的:将函数作为参数传递给被调函数(用来构建回调函数)
回调函数-->以下三个会用到
1.创建线程pthread_creat()
2.信号处理函数signal()
3.操作数据库获取数据sqlite3_exec()
特点:
1.事件触发 2.自动运行 3.使用函数指针传参 1.2.是功能特点 3.是代码特点
处理信号的方式
1.忽略
2.默认
3.捕捉(信号处理函数)
#include
#include
void fun1(int sig)
{
printf("Ctrl+c\n");//输入 Ctrl+c 时的响应
}
void fun2()
{
printf("Ctrl+\\\n");//输入 Ctrl+\ 时的响应
}
void fun3()
{
printf("Ctrl+z\n");//输入 Ctrl+z 时的响应
}
int main()
{
signal(SIGINT,fun1);
signal(SIGQUIT,fun2);
signal(SIGTSTP,fun3);
while(1)
{
printf("好好学习,天天向上\n");
sleep(1);
}
return 0;
}
4.const修饰指针
const int *a;
可以更改指针的指向,但无法通过指针修改指针指向的对象(但是可以直接通过变量修改)
使用地址传递的时候,主调函数不希望被调函数修改主调函数的值的时候,就可以通过定义const来达到这个目的
int *const a;
无法改变指针的指向,但是可以通过指针修改指针指向的对象
const int *const a;、
指针的指向和指针指向的对象都无法修改
5.指针数组 与 main()传参
指针数组:存放指针的数组
char *str1 = "apple";
char *str2 = "orange";
char *str3 = "banana";
char *str4 = "watermelon";
char *str5 = "lemon";
//相当于:
char *str[5];
str[0] = "apple";
str[1] = "orange";
str[2] = "banana";
str[3] = "watermelon";
str[4] = "lemon";
main()函数的参数有两个
1.argc(argument count) :命令行参数个数
2.argv(argument vector) :命令行参数向量表
有参数证明有主调函数-->内核是main函数的主调函数-->因此main函数的return 0;也是给内核看的 -->0真;1假
shell编程-->$0;$#;……
命令行传参:
#include
int main(int argc,const char *argv[]) //argc:输入命令行的条数,每条命令以空格为分界
{ //argv[]:记录每条命令的内容
printf("argc is %d\n",argc);
int i;
for(i = 0; i < argc; i++) //循环,显示出所有命令行的内容
{
printf("*argv[%d] is %s\n",i,argv[i]);
}
return 0;
}
6.动态内存分配
前提:空类型指针:void *p --> 未指向特定类型的指针 泛指所有数据类型的指针
-->不能直接使用,使用时必须强转为特定的指针类型
1.动态内存分配(堆区)
memory allocation
头文件:#include
void *malloc(unsigned int size)
功能:使用malloc()在堆区开辟内存空间,申请内存空间的大小由malloc()参数决定
若malloc()申请内存成功,则返回内存的首地址(这时返回的是空类型指针);若申请内存失败-->则返回NULL
注意:使用malloc()申请内存空间需要进行成功/失败的判定
#include
#include
int main()
{
int len,i;
printf("请输入学生的人数:");
scanf("%d",&len); //输入数量,申请一定大小的空间
int *p;
if((p = (int *)malloc(sizeof(int)*len))==NULL) //malloc申请空间,并判断是否申请成功
{
perror("Can't malloc");
return 0;
}
for(i = 0; i < len; i++) //循环输入每一个人的信息
{
printf("请输入第%d个学生的成绩:",i+1);
scanf("%d",&p[i]);
}
for(i = 0; i < len; i++) //不做处理,直接循环输出输入的信息
{
printf("%d ",p[i]);
}
printf("\n");
return 0;
}
#include
#include
void bubble(int a[],int len) //传入带有数据的数组,按照从小到大顺序,进行冒泡排序
{
int i,j;
for(i = 0; i < len; i++)
{
for(j = 0; j < len-i-1; j++)
{
if(a[j] > a[j+1])
{
a[j] ^= a[j+1];
a[j+1] ^= a[j];
a[j] ^= a[j+1];
}
}
}
}
void print(int a[],int len) //输出函数,输入数组及数组长度
{
int i;
for(i = 0; i < len; i++)
{
printf("%d ",a[i]);
}
printf("\n");
}
int *getmemory(int len) //malloc 申请堆区空间
{
int *p;
int i;
if((p = (int *)malloc(sizeof(int)*len))==NULL) //申请并判断是否申请成功
{
perror("Can't malloc");
return NULL;
}
return p; //返回申请空间的首地址
}
int main()
{
int i,j,len;
printf("请输入学生的人数:");
scanf("%d",&len); //根据输入,计算需要申请空间的大小(人数)
int *p;
p = getmemory(len); //指针 p 接收malloc申请的空间首地址
for(i = 0; i < len; i++) //循环输入每个学生的数据
{
printf("请输入第%d个学生的成绩:",i+1);
scanf("%d",&p[i]);
}
bubble(p,len); //冒泡排序(小-->大)
print(p,len); //输出函数
return 0;
}
2.使用free()回收malloc()申请的内存
申请的是使用权,free时归还的也是使用权,拥有权一直属于操作系统
原型:void free(void *p);
free(p);
绝对不可以free两次-->free掉一次后,原来的指针就变成了野指针,绝对不能操作野指针
free掉一次后,把原来的指针置空 =NULL