1.指针变量及基本用法
int main(int argc, const char * argv[]) {
@autoreleasepool {
int a=100;
int* point;
point=&a;
NSLog(@"%p",point);//输出0x7ffeefbff5ac,为什么总是这个地址
NSLog(@"%d",*point);//把值取出
}
}
输出
2020-05-14 17:25:43.195622+0800 EX003[866:27684] 0x7ffeefbff5ac
2020-05-14 17:25:43.195895+0800 EX003[866:27684] 100
2.指针变量作为函数参数
#import <Foundation/Foundation.h>
void swap(int* p1,int* p2){
int temp=*p1;
*p1=*p2;
*p2=temp;//这里只传了值,并没有传地址
p1=p2=nil;
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
int a=5;
int b=10;
NSLog(@"交换前a的值为:%d,b的值为:%d",a,b);
NSLog(@"交换前a的指针为%p,b的指针为%p",&a,&b);
int* pa=&a;
int* pb=&b;
swap(pa, pb);
NSLog(@"交换后a的值为:%d,b的值为:%d",a,b);
NSLog(@"交换后pa的指针为%p,pb的指针为%p",pa,pb);
}
}
输出:
2020-05-14 19:56:59.761501+0800 EX003[1279:65154] 交换前a的值为:5,b的值为:10
2020-05-14 19:56:59.761803+0800 EX003[1279:65154] 交换前a的指针为0x7ffeefbff5ac,b的指针为0x7ffeefbff5a8
2020-05-14 19:56:59.761835+0800 EX003[1279:65154] 交换后a的值为:10,b的值为:5
2020-05-14 19:56:59.761859+0800 EX003[1279:65154] 交换后pa的指针为0x7ffeefbff5ac,pb的指针为0x7ffeefbff5a8
3.指向数组的指针变量
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
int myarray[]={1,2,3,4,5};
int* parray1=&myarray[0];
int* parray2=myarray;
NSLog(@"指向的指针为%p",parray1);//首元素地址和数组名指向同一个地址
NSLog(@"指向的指针为%p",parray2);
}
}
输出:
2020-05-14 20:34:44.551895+0800 EX003[1437:75287] 指向的指针为0x7ffeefbff5a0
2020-05-14 20:34:44.552200+0800 EX003[1437:75287] 指向的指针为0x7ffeefbff5a0
4.指针运算
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
int myarray[]={1,2,3,4,5};
int* parray1=&myarray[0];
int* parray2=myarray;
NSLog(@"指向的指针为%p",parray1);//首元素地址和数组名指向同一个地址
NSLog(@"指向的指针为%p",parray2);
NSLog(@"--------");
NSLog(@"数组首元素%d",*parray1);
parray1+=2;
NSLog(@"数组指针+2后为%d",*parray1);
}
}
输出
2020-05-14 21:23:43.164989+0800 EX003[1519:88016] 指向的指针为0x7ffeefbff5a0
2020-05-14 21:23:43.165291+0800 EX003[1519:88016] 指向的指针为0x7ffeefbff5a0
2020-05-14 21:23:43.165321+0800 EX003[1519:88016] --------
2020-05-14 21:23:43.165346+0800 EX003[1519:88016] 数组首元素1
2020-05-14 21:23:43.165369+0800 EX003[1519:88016] 数组指针+2后为3
5.指针运算,使用指针遍历数组
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
int myarray[]={1,2,3,4,5};
for (int i=0,length=sizeof(myarray)/sizeof(myarray[0]); i<length; i++) {
NSLog(@"%d",*(myarray+i));//通过指针加法来访问数组
}
NSLog(@"------");
for (int* p=myarray,length=sizeof(myarray)/sizeof(myarray[0]); p<myarray+length; p++) {
NSLog(@"%d",*p);//通过指针来访问数组
}
}
}
输出:
2020-05-14 21:53:54.085506+0800 EX003[1584:96489] 1
2020-05-14 21:53:54.085783+0800 EX003[1584:96489] 2
2020-05-14 21:53:54.085810+0800 EX003[1584:96489] 3
2020-05-14 21:53:54.085829+0800 EX003[1584:96489] 4
2020-05-14 21:53:54.085845+0800 EX003[1584:96489] 5
2020-05-14 21:53:54.085863+0800 EX003[1584:96489] ------
2020-05-14 21:53:54.085879+0800 EX003[1584:96489] 1
2020-05-14 21:53:54.085895+0800 EX003[1584:96489] 2
2020-05-14 21:53:54.085911+0800 EX003[1584:96489] 3
2020-05-14 21:53:54.085927+0800 EX003[1584:96489] 4
2020-05-14 21:53:54.085969+0800 EX003[1584:96489] 5
6.指向多维数组的指针变量
int main(int argc, const char * argv[]) {
@autoreleasepool {
float arr[3][4]={
{1.2,3.4,4.5,6.1},
{7,3,4,8},
{3,9,2,1}
};
for (float* p=arr[0]; p<arr[0]+12; p++) {//指针指向数组的第一维的指针,从这个地址向下移动12个元素(3*4)
if ((p-arr[0])%4==0) {//p地址递增之后,根据移动的距离每4个元素换个行
printf("\n");
}
printf("%.1f, ",*p);
}
}
}
输出
1.2, 3.4, 4.5, 6.1,
7.0, 3.0, 4.0, 8.0,
3.0, 9.0, 2.0, 1.0,
7.使用字符指针表示字符串
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
char* str="hello world!";
NSLog(@"%s",str);
str+=7;
NSLog(@"%s",str);
}
}
8.字符指针作为函数参数
#import <Foundation/Foundation.h>
void copyString(char* to,char* from){
while(*from){//如果from指针指向的字符部位\0
*(to++)=*(from++);
}
*to='\0';
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
char* str="C语言的字符串在底层";
char* receive[100];
copyString(receive, str);
NSLog(@"%s",receive);
copyString(receive, "由于指针变量支持加法运算");
NSLog(@"%s",receive);
}
}
输出:
2020-05-14 23:35:19.577413+0800 EX003[1994:136273] C语言的字符串在底层
2020-05-14 23:35:19.577734+0800 EX003[1994:136273] 由于指针变量支持加法运算
9.用函数指针变量调用函数
C语言允许使用一个指针变量来指向概函数
1、定义函数指针变量的语法格式为:
函数返回值类型(*指针变量名)()
2、将任何已有的函数赋值给函数指针变量
fnPt=avg
3、使用函数指针变量来调用函数。
(*函数指针变量)(参数)
#import <Foundation/Foundation.h>
int max(int* data,int lenght){
int max=*data;
for (int* p=data; p<data+lenght; p++) {
if(*p>max){
max=*p;
}
}
return max;
}
int aver(int* data,int length){
int sum=0;
for (int* p=data; p<data+length; p++) {
sum+=*p;
}
return sum/length;
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
int data[]={1,3,56,788,3,32,23,54,345};
//定义指向函数的指针变量,fnpt,并将max函数的入口赋值给fnPt
int (*fnpt)()=max;
NSLog(@"最大值为:%d",(*fnpt)(data,9));//这里数组名就是指针
//将averg函数如克直接赋值给fnpt函数指针
fnpt=aver;
NSLog(@"平均值为:%d",(*fnpt)(data,9));
}
}
输出
2020-05-15 00:31:52.625729+0800 EX003[2107:154882] 最大值为:788
2020-05-15 00:31:52.626052+0800 EX003[2107:154882] 平均值为:145
10.用函数指针变量作为函数参数
#import <Foundation/Foundation.h>
void map(int* data,int length,int (*fn)()){
for (int* p=data; p<data+length; p++) {
printf("%d, ",(*fn)(*p));
}
printf("\n");
}
int nochange(int val){
return val;
}
int square(int val){
return val*val;
}
int cube(int val){
return val*val*val;
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
int data[]={1,3,5,7,3,32,23,54,45};
//三次调用map函数,传入三个不同的函数进去
map(data,9,nochange);
map(data,9,square);
map(data,9,cube);
}
}
输出:
1, 3, 5, 7, 3, 32, 23, 54, 45,
1, 9, 25, 49, 9, 1024, 529, 2916, 2025,
1, 27, 125, 343, 27, 32768, 12167, 157464, 91125,
11.返回指针的函数
为了保证返回的指针指向被调用函数中的局部变量,该局部变量应该使用static修饰,或者指向main函数中的变量
#import <Foundation/Foundation.h>
#define LENGTH 9
int* map(int* data,int length,int (*fn)()){
static int result[LENGTH];//使用的是静态的数组
int i=0;
for (int* p=data; p<data+length; p++) {
result[i++]=(*fn)(*p);
}
printf("\n");
return result;
}
int nochange(int val){
return val;
}
int square(int val){
return val*val;
}
int cube(int val){
return val*val*val;
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
int data[]={1,3,5,7,3,32,23,54,45};
//三次调用map函数,传入三个不同的函数进去,并返回三个数组
int* arry1=map(data,9,nochange);
for (int i=0; i<LENGTH; i++) {
printf("%d, ",*(arry1+i));
}
int* arry2=map(data,9,square);
for (int i=0; i<LENGTH; i++) {
printf("%d, ",*(arry2+i));
}
int* arry3=map(data,9,cube);
for (int i=0; i<LENGTH; i++) {
printf("%d, ",*(arry3+i));
}
}
}
输出:
1, 3, 5, 7, 3, 32, 23, 54, 45,
1, 9, 25, 49, 9, 1024, 529, 2916, 2025,
1, 27, 125, 343, 27, 32768, 12167, 157464, 91125,
12.指针数组与main()函数形参与指向指针变量的指针
指针数组(数组元素用存放指针变量的数组)声明格式:
类型* 数组变量名[长度]
指向指针的指针格式为:
类型 ** 变量名如
int ** pt=&p
反过来,取出指向指针的指针的值,则需要两个**来获得真实的值
#import <Foundation/Foundation.h>
void dowork(int* age[],int len){
for (int i=0; i<len; i++) {
printf("指针:%p----元素值%d\n",age+i,**(age+i));
}
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
int* age[5];
int a[]={1,2,3,4,5};
for (int i=0; i<5; i++) {
age[i]=&a[i];
}
dowork(age, 5);
}
}
输出
指针:0x7ffeefbff590----元素值1
指针:0x7ffeefbff598----元素值2
指针:0x7ffeefbff5a0----元素值3
指针:0x7ffeefbff5a8----元素值4
指针:0x7ffeefbff5b0----元素值5
13.结构体的定义及使用(一种简化的类)
格式:
struct 结构体类型名
{
//成员列表
}
struct Person{
NSString *name;
int age;
};
int main(int argc, const char * argv[]) {
@autoreleasepool {
struct Person{
NSString *name;
int age;
};
struct Person zhangsan;
zhangsan.name=@"张三";
zhangsan.age=34;
NSLog(@"%@",zhangsan.name);
NSLog(@"%d",zhangsan.age);
}
}
输出
2020-05-15 10:31:44.697597+0800 EX003[811:20383] 张三
2020-05-15 10:31:44.697873+0800 EX003[811:20383] 34
14.使用预编译指令将结构体的使用简化
#import <Foundation/Foundation.h>
#define PERSON struct Person
int main(int argc, const char * argv[]) {
@autoreleasepool {
struct Person{
NSString *name;
int age;
};
PERSON zhangsan;//通过预编译来写
zhangsan.name=@"张三";
zhangsan.age=34;
NSLog(@"%@",zhangsan.name);
NSLog(@"%d",zhangsan.age);
}
}
15.同时定义结构体及声明变量
格式:
struct 结构体名{
//成员变量
} 结构体变量名1,结构体变量名2;
#import <Foundation/Foundation.h>
#define PERSON struct Person
int main(int argc, const char * argv[]) {
@autoreleasepool {
struct Person{
NSString *name;
int age;
} zhangsan;
zhangsan.name=@"张三";
zhangsan.age=34;
PERSON lisi={@"李四",43};//只有在声明结构体变量时可以使用这种方式初始化,声明过后只能单个成员初始化
NSLog(@"%@",zhangsan.name);
NSLog(@"%d",zhangsan.age);
NSLog(@"----");
NSLog(@"%@",lisi.name);
NSLog(@"%d",lisi.age);
}
}
输出
2020-05-15 11:25:41.308957+0800 EX003[1075:40662] 张三
2020-05-15 11:25:41.309229+0800 EX003[1075:40662] 34
2020-05-15 11:25:41.309257+0800 EX003[1075:40662] ----
2020-05-15 11:25:41.309283+0800 EX003[1075:40662] 李四
2020-05-15 11:25:41.309304+0800 EX003[1075:40662] 43
16.结构体数组
#import <Foundation/Foundation.h>
#define PERSON struct Person
int main(int argc, const char * argv[]) {
@autoreleasepool {
struct Person{
NSString *name;
int age;
};
PERSON persons[]={
{@"张三",34},
{@"李四",23},
{@"王二",44}
};
for (int i=0; i<3; i++) {
NSLog(@"%@---%d",persons[i].name,persons[i].age);
}
}
}
输出
2020-05-15 14:18:49.040563+0800 EX003[2707:109076] 张三—34
2020-05-15 14:18:49.040900+0800 EX003[2707:109076] 李四—23
2020-05-15 14:18:49.040932+0800 EX003[2707:109076] 王二—44
17.定义及使用块(类似于匿名函数)
定义块的语法
^[块返回值类型](形参类型1 形参1,形参类型2 形参2)
定义块变量
块返回值类型 (^块变量名)(形参类型1,形参类型2)
定义块变量时,无须声明形参名,只要指定形参类型即可,无需形参则使用void
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
//定义不带参、无返回值的块
void (^printStr)(void)=^(void){
NSLog(@"调用快的语法与调用函数完全相同");
};
printStr();
//定义带参、返回值的块
double (^printDouble)(double,double)=^(double width,double height){
return width*height;
};
NSLog(@"%g",printDouble(15.34,34.32)) ;
//定义快变量,再将块赋值给指定的快变量
void (^printStr2)(NSString *);
printStr2=^(NSString *info){
NSLog(@"%@",info);
};
printStr2(@"块可以访问程序中局部变量的值");
}
}
输出:
2020-05-15 15:26:40.796611+0800 EX003[3569:144410] 调用快的语法与调用函数完全相同
2020-05-15 15:26:40.796906+0800 EX003[3569:144410] 526.469
2020-05-15 15:26:40.796972+0800 EX003[3569:144410] 块可以访问程序中局部变量的值
18.块与局部变量
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
int my=20;
void (^printMy)(void)=^(void){//块已经捕获了局部变脸my
//my=30;//不可以对局部变量赋值
NSLog(@"%d",my);
};
my=45;//这里即便改变了局部变量my,但是之前已经被捕获了,这次修改并不影响后面块的调用
printMy();
}
}
输出:
20
如果希望不被捕获,则需要将该局部变量前加上__block(这里是双下划线)
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
__block int my=20;
void (^printMy)(void)=^(void){//块已经捕获了局部变脸my
//运行时访问,获取局部变量的值,此处输出45
NSLog(@"%d",my);
//尝试对局部变量赋值时可以的
my=30;
NSLog(@"%d",my);
};
my=45;//这里即便改变了局部变量my,但是之前已经被捕获了,这次修改并不影响后面块的调用
printMy();
}
}
输出
2020-05-15 16:22:15.762446+0800 EX003[4183:169913] 45
2020-05-15 16:22:15.762751+0800 EX003[4183:169913] 30