1.1指针是什么

关于地址:

在程序中定义一个变量系统就会分配内存单元,根据变量类型去分配一定空间的长度。每一个字节都有一个编号,这就是“地址”。

通过地址能找到变量单元,所以我们说该地址指向该变量单元,因此形象地将地址称为指针。

3.4用数组名作函数参数

首先要知道,数组在程序中我们定义一个数组例如:int a【100】;数组名a的含义是&a【0】,

所以本质上是指针变量(因为只有指针变量才能储存地址)

所以下面的两种声明是等价的:

void hanshu(int a[],int n);
void hanshu(int* a;int n);

第一个函数的作用都是接收一个数组的首元素的地址。

下面是用指针方法让数组a中的函数倒序输出:

一开始我还写错了

#include<stdio.h>
main()
{int a[10]={1,2,3,4,5,6,7,8,9,10};int* p,* s;int temp;p=a;s=a+9;while(p<s){temp=p;p=s;s=temp;s--;p++;   }p=a;for(;p<a+10;p++)printf("%d",*p);}

上述程序的结果是次序没变,为什么呢,我不是交换地址了吗?

那确实一直在改变指针变量p和s的指向,a【i】的值根本没有改变。

#include<stdio.h>
main()
{int a[10]={1,2,3,4,5,6,7,8,9,10};int* p,* s;int temp;p=a;s=a+9;while(p<s){temp=*p;*p=*s;*s=temp;s--;p++;   }p=a;//或者这里让s=(n-1)/2也可以;for(;p<a+10;p++)printf("%d",*p);}

3.5指向多维数组的指针

关于多维函数的地址

在一维数组中,例如a[4],a[1]是一个数组元素,a是一个数组名代表&a[0](即为首个元素的地址)

but神奇的事情来了,在多维数组中比如a[4][3]中a[1]是一个地址,因为此时的a[1]不是数组元素而是代表由3个整型变量所组成的一维数组,a[1]代表第一行的第一个元素的地址即&a[1][0]。而数组名a代表的是首行的起始地址&a[0],a+1代表序号为序号为1的行的起始地址。

a[0],a[1],a[2]是一维数组名,代表首元素的地址。

那么要具体到列的元素的地址怎么表示呢?

&a[0][1]等价于a[0]+1,之前我们说过地址加1是加上该类型地址的字节数。

用指向数组的指针作函数参数

若想定义一个指向一维数组的指针,可以这样定义

int (*p)【4】;

它表示指针变量p指向由四个整形元素组成的一维数组。

下面我们看一段程序:

#include<stdio.h>
void research(int (*p)[4],int n)
{int i=0;for(i=0;i<=3;i++)printf(" %d",  *(*(p+n-1)+i));
}void average(int *p)
{int i=1;int sum=0;for(i=1;i<=12;i++)sum+=*(p++);printf("%f",sum/12.0);
}
main()
{   int grade[3][4]={1,2,3,4,5,6,7,8,2,2,3,4};int (*p)[4]=grade;research(p,1);average(*p);
}

12个人的成绩,我编写了两个函数分别去输出平均成绩和某个人的全部成绩,一开始定义的指针p是指向一维数组的,这与research函数的形参要求相符(接收行的地址),然而average函数要求一个指向列的地址,于是用的实参是*p以满足要求。

4.1 通过指针引用字符串

首先记住一句话,在c语言中,字符串都是字符数组。它就是按字符数组去处理的。

另外在定义字符串常量的时候字符数组的实际长度比字符元素多1,因为会在末尾架上‘\0'

直接看两段程序:

#include<stdio.h>
main()
{
char string[]="I Love You";
printf("%s,%c",string,string[5]);
char *p=string;
printf("%s",*p);
}

1结果:第一个printf输出了i love you和第六个字符 e,第二个输出了了i love you。

2关于指针指向:定义了一个字符类型的指针变量,要理解为该指针变量p指向了该字符串的第一个数组元素i。

3关于%s:对于%s在输出时会输出指针变量p指向的字符然后使得p加1(指向下一个字符)直到遇到’\0'为止

4注意:另外要记住,c语言中没有字符串变量,只有字符变量。

有关定义:

char *p="i love you";

等价于

char *p;
p ="i love you";

下面看一个将字符串b复制到字符串a的例子:

#include<stdio.h>
main()
{char a[]="i love you,my baby";char b[30];char *p1=a,*p2=b;int i=0;for(;*p1!='\0';p1++,p2++)*p2=*p1;*p2='\0';p2=b;printf("%s",p2);
}

两个字符型的指针分别赋值然后加加而已啦。

#include<stdio.h>
main()
{char a[]="i love you,my baby";char b[30];b[18]='C';char *p1=a,*p2=b;int i=0;for(;*p1!='\0';p1++,p2++)*p2=*p1;*p2='\0';printf("%s",b);
}

其实有没有*p2='\0'都行因为好像剩下没有赋值的自动为0了(已测试)这里是没问题,但是在后边有吧一个段的字符串复制到长的上去,那个时候不加就会出错哦。

4.2字符指针作函数参数

下面是是一个copy函数。

5.1 指向函数的指针

当你定义了一个函数的时候,在编译时会把函数的源代码转换为可执行代码并分配一定的储存空间,其实这段空间有一个起始地址也称为函数的入口地址。函数名就代表这个起始地址,调用函数时可以从函数名获取它的起始地址并执行函数代码。

可以定义一个指针变量指向某种类型的函数例如:

int (*p)(int,int);

定义p是一个指向函数的指针变量,它可以指向函数类型为整形且有两个整形参数的函数,指针变量p的类型用int(*)(int,int)表示。

定义和使用指向函数的指针变量

直接看程序:

#include<stdio.h>
int max(int x,int y)
{return (x>y?x:y);
}
int min(int x,int y)
{return (x>y?y:x);
}
main()
{
int (*p)(int ,int );
int n,a,b;
scanf("%d %d",&a,&b);
scanf("%d",&n);
if(n==1)
{p=max; printf("%d",(*p)(a,b));}
if(n==2)
{p=min; printf("%d",(*p)(a,b));}
}

定义了一个指向函数的指针p,注意只能指向和指针变量相同基类型的函数。

这里注意要让指针指向函数时不要忘记*p两边的括号(*p)一开始我就忘了,哎。

5.4 用指向函数的指针做函数参数

指向函数的指针变量的一个重要用途是把函数的入口地址作为参数传递到其他函数。

这个就不多说了,在定义函数的时候这样

void fun(int(*p1)(int),int(*p2)(int,int))
{
int a,b,i=1,j=2;
a=(*p1)(i);
b=(*p2)(i,j):
}

在调用的时候直接将实参(函数名)传入fun接受函数地址的地方即可。

6.1 返回指针值的函数

看这个 int* a(int x,int y)   这难道是指向函数的指针吗?!不.......不对,在*a两边没有加括号,这说明定义了一个函数a而且有两个形参,该函数的类型是int* 型,也就是说返回值是一个指针!!

下面看一个查找学生成绩的程序:

#include<stdio.h>
main()
{  int n,i; int* research(int (*p)[4],int n);int grade[][4]={{22,44,65,22},{88,66,43,11},{6,78,99,44}};printf("please enter the number you want to research");scanf("%d",&n);int *k=research(grade,n);for(i=0;i<4;i++)printf("%  d",*(k+i));
}int* research(int (*p)[4],int n){int *pt;pt= *(p+n-1)+0;return pt;}

二维数组grade存放三个学生每个人四门成绩,research返回第n个人grade【n】【0】的地址之后输出即可。

最后看一个找出有一门不合格的成绩的学生并输出起全部成绩。

7.1指针数组和多重指针

一个数组,如果其元素全为指针类型数据,这就是指针数组。

int *p[4];什么,这难道不是指向 由四个整形元素组成的一维数组的 指针吗?!显然由于[ ]的优先级比较高,因此先运算p[4],这显然是一个数组,而这个数组又是一个int *类型的,所以是指针数组。

应用场景

使指针数组指向多个字符串进行排序:

#include<stdio.h>
#include<string.h>
main()
{void sort(char *name[],int n);void print(char* name[],int n);char* name[]={"Follow me","Basic","i love you","my honey","fuck me"};//定义了一个指针数组使得它指向这5个字符串sort(name,5);print(name,5); }void sort(char* name[],int n){int i,j,k;char* temp;for(i=0;i<n-1;i++){for(k=i+1;k<n;k++)if(strcmp(name[i],name[k])>0){temp=name[i];name[i]=name[k];name[k]=temp;}}}void print(char* name[],int n){int i=0;for(;i<n;i++)printf("%s\n",name[i]);}

我们定义了一个字符型的指针数组,它分别指向5个字符串,之后将该指针数组的首地址传入函数中进行处理。strcmp是程序提供的字符串比较函数,name[k]和name[i]是第i个和第k个字符串首字符的地址。它的值为若name[i]指向的字符串大于name[k]的,则返回正数,若相等则返回0,若小于则返回负数。

7.2指向指针的指针变量

上面我们已经讲了指针数组,即数组元素由指针组成。而我们知道,数组名表示该数组第一个元素的地址,刚上面的name则是&name[0],name+i就是&name[i]。

我们可以定义一个指向指针数组元素的指针,p就是一个指向指针型数据的指针变量,look!

char **p;

这个要分开来看,(*p)代表它是一个指针变量,char* 代表它的基类型(即它可以指向的数据的类型)显然是字符型的指针变量。思考下面的程序会输出什么:

printf("%d %s",*p,*p);

答案是输出了name[2]的值(是一个地址)和name[2]代表的字符串“Basic”。

关于为什么由%s输出了“Basic”其实这个谭浩强的书没有细讲,在“C primer plus”上讲的很清楚,一个字符串加上双引号就是字符串面常量,加上双引号就是地址了指向第一个字符的地址,而当指针指向它的话算是引用(回去我在看看,没学精这部分)

8.1 动态内存分配与指向它的指针变量

之前我们讲过全局变量和局部变量的概念,全局变量是分配在内存中的静态存储区的,非静态存储区的局部变量(包括形参)是分配在内存中的动态存储区的,这个存储区称为

除此之外,c语言还允许建立内存动态分配区域,以存放一些临时用的数据,随时用随时开辟,不需要用了就释放,称为 区。

建立内存的动态分配(4个函数)

1、用 malloc 函数开辟动态存储区

函数原型为:

void *malloc(unsigned int size);

作用为在内存的动态区域分配一个长度为size的连续空间,形参size的类型定为无符号整形(非负),该函数的返回值为分配区域第一个字节的地址(因为函数类型是指针嘛)

malloc(100);开辟100个字节的临时分配域,返回值为第一个字节的地址。

注意:函数类型为void 只返回一个纯地址而不指向任何类型的数据,如果函数未能成功的执行则返回空指针(NULL)。

2、用 calloc函数 开辟动态存储区

函数的原型为

void *calloc(unsigned n,unsigned size);

它的作用是开辟n个长度为size的连续空间,空间一般较大,足以储存一个数组。

用calloc函数可以为一维数组开辟内存储存空间,n为元素的个数,每个元素长度为size,这就是动态数组。函数的返回值指向第一个自节的地址,如果不成功则返回NULL。

如 p=calloc(50,4);

3、用 realloc函数 重新分配动态存储区

函数原型为

void *realloc(void *p,unsigned int size);

如果已经通过malloc函数或者calloc函数分配了动态存储区域,若想改变大小,可以通过realloc函数重新分配。

用realloc函数将p指向的动态空间的大小改变为size。p的值不变。如果重分配不成功,返回NULL,如 realloc(p,50);//将p所指向的已分配的动态空间改为50字节

4、用 free函数 释放动态存储区

函数原型为:

void free(void *p);

释放p所指向的存储空间,p为最近一次调用malloc函数或者calloc函数时得到的返回值。

free(p);free函数无返回值。

以上四个函数的声明在stdlib.h头文件中,要用#include<stdlib.h>包含到程序文件中。

void指针类型

C语言学习笔记(指针篇)相关推荐

  1. R语言学习笔记——入门篇:第一章-R语言介绍

    R语言 R语言学习笔记--入门篇:第一章-R语言介绍 文章目录 R语言 一.R语言简介 1.1.R语言的应用方向 1.2.R语言的特点 二.R软件的安装 2.1.Windows/Mac 2.2.Lin ...

  2. R语言学习笔记——高级篇:第十四章-主成分分析和因子分析

    R语言 R语言学习笔记--高级篇:第十四章-主成分分析和因子分析 文章目录 R语言 前言 一.R中的主成分和因子分析 二.主成分分析 2.1.判断主成分的个数 2.2.提取主成分 2.3.主成分旋转 ...

  3. R语言学习笔记——入门篇:第三章-图形初阶

    R语言 R语言学习笔记--入门篇:第三章-图形初阶 文章目录 R语言 一.使用图形 1.1.基础绘图函数:plot( ) 1.2.图形控制函数:dev( ) 补充--直方图函数:hist( ) 补充- ...

  4. 易语言学习笔记——命令篇

    易语言学习笔记20180711 一. 命令概述 1.     什么是命令:命令是一个功能调用的开始. 2.     命令的参数:调用一个功能方法时候输入的数据或者条件. 3.     命令的返回值:调 ...

  5. 易语言学习笔记——基础篇

    易语言学习笔记20180710 一. 易语言的数据类型可以分为基本数据类型和特殊数据类型 1.     其中基本数据类型分为: ①   数值型 ②   逻辑型 ③   日期时间型 ④   文本型 ⑤  ...

  6. 易语言学习笔记——入门篇

    易语言学习笔记20180709 最早接触易语言是三年前的事情了,那时候是因为DNF这个游戏我才知道了易语言这个编程语言,当时对他就非常的憧憬.只不过那时候易语言的学习资源比较少,而且自身的学业比较重就 ...

  7. C语言学习笔记——指针章节

    学习小结 c语言指针学习笔记汇总 #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h>//指针 //在计算机科学中,指针是编程语言的一个对 ...

  8. C语言学习笔记---指针

    C语言要玩的好,指针是核心,但是指针在学习的时候看教程往往感觉一看就明白,但是实际用的时候一用就错,而且还不知道错在哪.为了更加深刻的了解指针,将学习过程记录下来,依次加深对指针的理解. 先看看一段测 ...

  9. c语言普通变量间接访问,C语言学习笔记-指针

    野指针问题 野指针是没有指向地址的指针,也就是该指针指向的地址是随机的. 因为指针的指向地址是随机的,所以很有可能指向不可访问的弟子,导致程序崩溃,或者访问了不该访问的地址,导致影响其他功能使用 为了 ...

  10. C语言学习笔记---指针和数组

    数组是相同类型的数据集合,会在内存中占用连续的一块内存.而指针是存储的一个地址,在内存中不会占用连续的内存. 先来写一段测试代码 void fun(void) {int i;int num[10]={ ...

最新文章

  1. UVa 167(八皇后)、POJ2258 The Settlers of Catan——记两个简单回溯搜索
  2. LeetCode-笔记-48.旋转图像
  3. 响应式开发一招致胜 学习视频 分享
  4. Unobtrusive JavaScript介绍
  5. 基于JAVA+SpringMVC+Mybatis+MYSQL的药方中医管理系统
  6. vSphere 高级特性FT配置与管理
  7. std::lexicographical_compare
  8. Android TextView 使用替换构建出不同样式的字符串
  9. 19. Element id 属性
  10. 知识图谱 - 知识体系构建与知识融合
  11. 机器学习导论——关于数据集的概念
  12. Android上边抽屉式标题,Android Navigation Drawer样式抽屉的使用
  13. 面了一个4年经验的测试工程师,自动化都不会也要15k,我真是醉了...
  14. Latex将文中的某一行设置成左对齐、右对齐
  15. [附源码]java毕业设计在线视频网站
  16. 51SCM_AD模块CS5550学习心得
  17. 144hz和60hz测试软件,144hz和60Hz显示器的区别有哪些?60Hz与144Hz显示器玩游戏差别对比评测...
  18. Spring bean的自动装配
  19. android 防录屏 sdk,如何使用DRM-X4.0保护Zoom Web SDK?(Zoom会议直播防录屏)
  20. Hive连接Spark报错java.sql.SQLException: null, message from server: Host 'datanode03' is blocked becaus

热门文章

  1. 字、半字、字节的区别
  2. javaGUI编写的键盘检测,利用GUI实现按键效果展示
  3. Sourcetree配置ssh客户端
  4. 树莓派搭建自动追番服务器详细教程|树莓派|Jellyfin|AutoBangumi|qBittorrent
  5. Pycharm的.log文件带问号标识无法打开解决方案
  6. 云杰恒指:6.11恒指期货早盘思路
  7. Centos Linux查看目录剩余空间大小
  8. 美国开餐馆需要什么证件?怎么让餐馆高效经营?
  9. java vue elementui 上传照片墙
  10. 通过java springboot实现阿里云dns动态解析