指针是什么

》》每一个内存单元只能同时存储一个数据,如何保证内存单元同时只能存储一个数据,可以使用编号的方式实现内存单元标记,此编号就是指针。

》》指针是一个变量,指针是存放着一个数据的内存地址而不是数据本身的值,其是查找数据的另一种方式

相关运算符

【&】在变量中取地址

【*】在地址中取变量

测试小程序:

  1. #include<stdio.h>
  2. void main() {
  3. int i = ;//定义一个变量,并赋初始值为10
  4. int *p = &i;//定义一个指针变量,并赋初始值为i的地址
  5. *p = ;
  6. printf("%d=%d", *p,i);//输出199=199
  7. printf("---%d---", p);//得到变量i的地址
  8. }

指针变量的类型

》》指针类型:int *、float*、long*、double*、char*等等

》》指针变量的类型需要与存储的数据类型相同

》》确定类型可以方便指针变量确定存储数据的大小,为数据寻找到结束符,如int类型占四个字节、char占一个字节。也方便指针使用加1或减1操作,如int加减1会跳动4个字节,char加减1会跳动两个字节。

指针的赋值

int i=10;  int *p=&i;

int *pp;

pp=p;

指针运算符:

*p++

等同于*(p++),运算优先级为从右到左,应该是先*p取值,然后地址移动一位,要区别与*(++p)。

  1. char *ch="";
  2. //printf("%c\r\n",*ch++);//输出0
  3. //printf("%c\r\n",*(ch++));//输出0
  4. printf("%c\r\n",*(++ch));//输出1

指针变量作为函数参数

  1. #include<stdio.h>
  2. //int *a1=&b1;
  3. void fun(int *a1, int* a2) {
  4.  
  5. *a1 = ;
  6. int ii = ;
  7. a2 = &ii;//让指针重新指向另外一个地址
  8. printf("得到的数据:%d,%d", *a1, *a2);//输出100,99
  9. }
  10. void main() {
  11. int b1 = , b2 = ;
  12. fun(&b1, &b2);
  13. printf("调用函数后:%d,%d", b1, b2);//输出100,2
  14. }

输出b2的结果并不是相同的值,是因为执行调用函数改变了实参指针变量的值,并不是改变了实参指针变量所指变量的值

数组作为函数参数

  1. #include<stdio.h>
  2. void fun1(int *arr){
  3. arr[]=;
  4. arr[]=;
  5. }
  6. void fun2(int arr[]){
  7. arr[]=;
  8. arr[]=;
  9. }
  10. void main(){
  11. //变量初始化
  12. int i;
  13. int a[]={,,,,,,};
  14. //函数调用
  15. fun1(a);
  16. fun2(a);
  17. //打印
  18. for(i=;i<sizeof(a)/sizeof(int);i++){
  19. printf("%d ",a[i]); //10 11 100 110 4 5 6
  20. }
  21. }

数组作为函数参数会自动退化为指针

函数形参如果是数组,不管下标是多少都会自动转换为数组的首地址指针

  1. #include<stdio.h>
  2.  
  3. void fun1(int *p){
  4. printf("%d",p[]);//
  5. }
  6. void fun2(int p[]){
  7. printf("%d",p[]);//
  8. }
  9.  
  10. void fun3(int p[]){
  11. printf("%d",p[]);//
  12. }
  13.  
  14. void fun4(char *p[]){
  15. printf("%s",p[]);//dong
  16. }
  17.  
  18. void fun5(char **p){
  19. printf("%s",p[]);//dong
  20. }
  21.  
  22. void main(){
  23. int ii[]={,,};
  24. fun1(ii);
  25. fun2(ii);
  26. fun3(ii);
  27. char *ch[]={"dong","xiao"};
  28. fun4(ch);
  29. fun5(ch);
  30. }

一维数组指针变量

数组名(如arr)代表元素的首地址,数组第一个元素的地址也是这个数组的首地址(如&arr[0])。

数组指针中使用加减1将跳到下一个或者上一个数组元素地址,与使用 &arr[n+1] 基本相同。

如果整数数组名为arr,运行int *p=arr,则*(p+3)、p[3]、*(arr+3)、arr[3]效果均是取出数组arr的第三个元素,在编译时arr[3]实际上是*(arr+3)处理的。

  1. #include<stdio.h>
  2. void main() {
  3. int arr[] = { ,,,, };
  4. int *p = arr;
  5. int *pp = &arr[];
  6. printf("%d", *(p+));//输出2
  7. }

函数数组参数

  1. #include<stdio.h>
  2. //等价于void fun(char a1[]) {
  3. void fun(char *a1) {
  4. *(a1 + ) = 'c';//改变第二个值的内容
  5. }
  6. void main() {
  7. char b1[] = { "" };
  8. fun(b1);
  9. printf("调用函数后:%s", b1);//输出: 12c456789
  10. }

二维数组指针变量

  1. #include<stdio.h>
  2. void main() {
  3. int a1[][] = { {,,},{,,} };
  4. int a[][] = { ,,,,, };
  5. printf("地址:%d==%d==%d==%d", a[], &a[][],*(a+),a+);//输出地址
  6. printf("%d===%d==%d", a[][], *(*(a + )+),*(a[]+));//得到值
  7. }

指针引用字符串

字符串常量【char *ch = "dong xiao dong";】表示其指向地址的内容不可变,但指向的地址是可变的;

字符串变量【char ch[] = "dong xiao dong";】其指向地址的内容可变。

  1. #include<stdio.h>
  2. void main() {
  3. //char *ch = "dong xiao dong"; //字符串常量,不可变
  4. char ch[] = "dong xiao dong"; //字符数组,可变
  5. ch[] = '';//字符串常量运行这条将报错
  6. printf("%s\n", ch);
  7. }

可变格式的输出函数:

  1. #include<stdio.h>
  2. void main() {
  3. char *ch = "dong xiao %d\n";
  4. printf(ch, );
  5. ch = "xiaoxiao%d\n";
  6. printf(ch, );
  7. char chh[] = "dongdong %d\n";
  8. printf(ch, );
  9. }

指向函数的指针

【int(*p)(int, int);//定义一个函数指针变量p】,第一个int表示返回值类型,第二个int和第三个int表示函数的参数类型。注意*p两侧的括号不能省略,表示p先与*结合,是指针变量,然后再于后面的()结合,()表示是函数,即该指针变量不是指向一般的变量,而是指向函数。如果写成“int * p(int,int);”,由于()优先级高于*,它相当于“int *(p(int,int))”,就成了声明一个p函数,并且这个函数的返回值是指向整型变量的指针。

返回值为int

  1. #include<stdio.h>
  2. void main() {
  3. int minto(int a, int b);//函数声明
  4. int(*p)(int, int);//定义一个函数指针变量p
  5. p = minto;//函数指针指向函数minto首地址
  6. int cc = (*p)(, );//调用函数
  7. printf("Min===%d", cc);
  8. }
  9.  
  10. int minto(int a, int b) {
  11. if(a > b) return b;
  12. else return a;
  13. }

无返回值:

  1. #include<stdio.h>
  2. void main() {
  3. void fun(int a);//函数声明
  4. void (*p)(int);//定义一个函数指针变量p
  5. p = fun;//函数指针指向函数fun首地址
  6. (*p)();//调用函数
  7. }
  8. void fun(int a) {
  9. printf("%d\n", a);
  10. }

指向函数指针作为函数的参数

  1. #include<stdio.h>
  2. void main() {
  3. int fun(int(*addpp)(int, int), int x, int y);//函数声明
  4. int add(int i, int j);
  5.  
  6. int ii=fun(add, , );//传递函数名和参数即可
  7. printf("输出相加的值为:%d", ii);
  8. }
  9.  
  10. //int (*addpp)(int,int);addpp=add;
  11. int fun(int (*addpp)(int,int),int x,int y){
  12. int cc = (*addpp)(x, y);
  13. return cc;
  14. }
  15.  
  16. int add(int i, int j) {
  17. return i + j;
  18. }

返回指针的函数

  1. #include<stdio.h>
  2. void main() {
  3. int* add(int i, int j);
  4. int *p = add(, );
  5. printf("输出相加的值为:%d", *p);
  6. }
  7.  
  8. int* add(int i, int j) {
  9. int aa = i + j;
  10. return &aa;//返回地址
  11. }

指针数组

一个数组其全部元素都存放着指针,就是指针数组【int * p[5];】

  1. #include<stdio.h>
  2. void main() {
  3. //指针数组
  4. char * p[] = { "dong1","xiao2","dong3","dong4" };
  5. printf("%s\n", p[]);
  6. }

进阶版

  1. #include<stdio.h>
  2. void main() {
  3. //指针数组(字符串)
  4. char * p[] = { "dong1","xiao2","dong3","dong4" };
  5. char **pp;
  6. pp = p;
  7. printf("%s\n", *(pp+));//转换一次就可以拿到对应字符串的首地址通过%s打印
  8.  
  9. //指针数组(整数)
  10. int a[]= {,,, };
  11. int * ip[] = { &a[],&a[],&a[],&a[],&a[]};
  12. int **ppp = ip;
  13. printf("%d\n", *(*ppp+));//转换第一次得到存储的指针,再次转换得到值
  14. }

void类型指针

  1. void a;//定义一个无类型变量,错误,不能确定分配的内存大小
  2. void *a;//定义一个无类型指针,可行,指针类型都是4个字节(32位,64位为8个字节)

void *p;表示指针变量p不指向一个确定的类型数据,它的作用仅仅是用来存放一个地址。

可以将任意类型的指针直接给void指针赋值,但是如果需要将void指针的赋值给其他类型的指针,则需要进行强制类型转换

  1. #include<stdio.h>
  2.  
  3. void fun1(void *i){
  4. int *p=(int *)i;//强制类型转换
  5. *p=;
  6. }
  7.  
  8. void main(){
  9. int ii=;
  10. fun1(&ii);
  11. printf("%d",ii);//输出100
  12. }

错误示范

1、

int *p=10; //等同于:int *p; p=10;

分析:非法操作,内存地址不能用户自定义。10相当于一个内存地址,该内存地址的值不确定且也不明确该地址是否可以直接访问,正确的应该是使用【&变量名】得到内存地址。

2、

  1. int f = 12.3;
  2. int *p;
  3. *p = &f; //错误1
  4. int ff = &f; //错误2

分析:指针(地址)必须赋值给指针变量

C语言指针收藏的更多相关文章

  1. C语言指针转换为intptr_t类型

    1.前言 今天在看代码时,发现将之一个指针赋值给一个intptr_t类型的变量.由于之前没有见过intptr_t这样数据类型,凭感觉认为intptr_t是int类型的指针.感觉很奇怪,为何要将一个指针 ...

  2. [转]C语言指针学习经验总结浅谈

    指针是C语言的难点和重点,但指针也是C语言的灵魂 . 这篇C语言指针学习经验总结主要是我入职以来学习C指针过程中的点滴记录.文档里面就不重复书上说得很清楚的概念性东西,只把一些说得不清楚或理解起来比较 ...

  3. 不可或缺 Windows Native (7) - C 语言: 指针

    [源码下载] 不可或缺 Windows Native (7) - C 语言: 指针 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 指针 示例cPointer.h #i ...

  4. C语言指针学习

    C语言学过好久了,对于其中的指针却没有非常明确的认识,趁着有机会来好好学习一下,总结一下学过的知识,知识来自C语言指针详解一文 一:指针的概念 指针是一个特殊的变量,里面存储的数值是内存里的一个地址. ...

  5. (转载)c语言指针学习

    前言 近期俄罗斯的陨石.四月的血月.五月北京的飞雪以及天朝各种血腥和混乱,给人一种不详的预感.佛祖说的末法时期,五浊恶世 ,十恶之世,人再无心法约束,道德沦丧,和现在正好吻合.尤其是在天朝,空气,水, ...

  6. 关于C语言指针的问题

    在学习关于C语言指针的时候,发现这样一个问题,代码如下: #include<stdio.h> #include<stdlib.h> #include<string.h&g ...

  7. C语言指针类型 强制转换

    关于C语言指针类型 强制转换  引用一篇文章: C语言中,任何一个变量都必须占有一个地址,而这个地址空间内的0-1代码就是这个变量的值.不同的数据类型占有的空间大小不一,但是他们都必须有个地址,而这个 ...

  8. C语言指针和数组知识总结(上)

    C语言指针和数组知识总结(上) 一.指针的基础 1.C语言中,变量的值能够通过指针来改变,打印指针的语句符号可以是:  %08x 2.指针的本质 指针的本质就是变量,那么既然是变量,那么一定会分配地址 ...

  9. C语言指针操作

    欢迎访问我的新博客:http://www.milkcu.com/blog/ 原文地址:http://www.milkcu.com/blog/archives/pointer-manipulation. ...

随机推荐

  1. NULL、0、nullptr

    C的NULL 在C语言中,我们使用NULL表示空指针,也就是我们可以写如下代码: int *i = NULL;foo_t *f = NULL; 实际上在C语言中,NULL通常被定义为如下: #defi ...

  2. CentOS7下安装pip和pip3

    1.首先检查linux有没有安装python-pip包,直接执行 yum install python-pip 2.没有python-pip包就执行命令 yum -y install epel-rel ...

  3. javascript 函数,事件

    1.函数字符串函数 var s=new string(); var ss="hello world"; var sss=""HELLO, WORLD" ...

  4. php学习笔记-获取表单数据

    在网页上经常要填写用户名和密码,点击确认按纽之后,用户名和密码经过前端处理之后发送到了服务器上,那么服务器端怎么获取到这些用户提交的数据呢?就是通过超级全局变量 _POST和_GET 先拿_POST做 ...

  5. php学习笔记-默认参数

    在定义函数的时候,我们可以把其中的一个参数变的特殊起来,使它有一个默认值,这个参数就叫默认参数.在调用这个函数的时候,你既可以给这个默认参数传递一个值,这样的话默认参数的值会被覆盖掉,也可以不给它传递 ...

  6. c++ 类中模版成员函数

    C++函数模版与类模版. template <class T> void SwapFunction(T &first, T &second){ }//函数模版 templa ...

  7. spring第三篇

    在昨天下午更新sprin第二篇中,叙述了将对象交给spring创建和管理,今天在spring第三篇中,主要写两个点一是spring的思想 二是spring中bean元素的属性配置. 1 spring思 ...

  8. 解决Spring MVC 对AOP不起作用的问题

    用的是 SSM3的框架 Spring MVC 3.1 + Spring 3.1 + Mybatis3.1 第一种情况: Spring MVC 和 Spring 整合的时候,SpringMVC的spri ...

  9. c#委托与事件、消息、WndProc用法(转)

    c#委托与事件 心得 c#用委托来实现事件通知机制.委托相当与c++函数指针.整个过程涉及一个呼叫者,一个被呼叫者,还有就是这个委托. - 实现步骤有以下几步: 1. 申明委托, 2.定义呼叫者和调用 ...

  10. 使用metasploit进行栈溢出攻击-3

    有了shellcode,就可以进行攻击了,但是要有漏洞才行,真实世界中的漏洞很复杂,并且很难发现,因此我专门做一个漏洞来进行攻击. 具体来说就是做一个简单的tcp server,里面包含明显的栈溢出漏 ...