指针基础

一 指针就是地址,地址就是指针.指针存储的是内存的地址.

二 指针的定义

1.&表示取址运算符,&a 可以取到 a 在内存中的地址;打印地址的占位符为(%p),printf(“%p\n”,&a);

2. 指针变量的定义

指针变量是用来存放地址的.

指针定义的格式:

类型数据  *变量名  =  初始值;

int *p = NULL;*在这里表示p 是一个指针变量,不是运算符.

printf(“%p\n”,p); 在打印指针的时候不需要使用取址运算符(&),因为指针本来就是地址.

*p 指针为空时,打印出来0x0的地址,为空.

int  a = 10;

p = &a;

printf(“%p\n”,p);

访问内存中的数据有两种方法:

1.直接访问内存中的数据.

printf(“%p\n”,a);

2. 通过指针进行访问.

*也可以作为取值运算符.* p 代表取到 p 指向内存中存储的数据  printf(“%d\n”,*p);

int a = 10,b = 20;

int *p1 = &a;

int *p2 = &b;

对指针重新赋值,意味着指针重指向,也就是说指针指向一个新的地址.

p1 = p2;p1指向 c 的首地址

printf(“*p1 = %d,* p2 = %d\n”,*p1,*p2);

int a = 15,b = 20;

int *p = &a;

int *p1 = &b;

单独的* p 表示取值,* p = 11 表示向 p 指向的内存中存入数据.

*p = 11;

printf(“%d\n”,a);

int *p3 = &a;

p3 = p1;

*p1 = 8;

printf(“a = %d,b = %d\n”,a,b);a = 11,b = 8

经典练习

int a = 6,b = 8,c = 10;

int *x = &a;

x = &c;

int *y = &b;

int *z = &c;

*z = 5;

*x = 12;

x = y;

*y = *x + *z;

printf(“a = %d,b = %d,c = %d\n”,a,b,c);

指针中常见的问题

1.内存编号比较小的存储单元,是由系统控制的,不允许访问.

int *p = NULL;

*p = 100;   error

2.野指针,定义时没有赋初始值,操作野指针是很危险的

int *p;

*p = 100;error

3.定义指针时,*怎么写?

int *p = NULL;推荐

int* p1 = NULL;

int *p1 = NULL;

int*p3 = NULL;

4.指针变量在内存中占几个字节

与数据类型无关,在32位操作系统下,指针所占字节数是4位,在64位操作系统中,指针所占字节数是8位.

printf(“%lu\n”,sizeof(long *));

5. 修饰指针变量数据类型的作用

a. 指针变量数据类型,决定*(取值运算符),取多少个字节的数据;

定义指针的数据类型一定要和指向数据的数据类型一致,这样才能把数据完整的取出来

int *p = NULL;

int a = 268;

p = &a;

printf(“%d\n”,*p);

char *c = NULL;

c = &a;

printf(“%d\n”,*c);

b.指针类型,决定指针变量加1操作时,跳转多少个字节

int *p = NULL;

printf(“%p\n”,p); //0x0

printf(“%p\n”,p+1);//0x4

printf(“%p\n”,p+2);//0x8

printf(“%p\n,p++);//打印的结果是:0x4   但是实际结果是:0x8

p+1 和  p++或++ p 的关系

相同:取到的都是下一个字节的地址

不同:++p和 p++ 造成指针的重指向

6.指针在数组中的应用

int a[5] = {1,2,3,4,5};

数组名就是数组元素的首地址

printf(“%p\n”,a);

printf(“%p\n”,&a[0]);

printf(“%p\n”,p);

printf(“%p\n”,a+1);

printf(“%p\n”,&a[1]);

printf(“%p\n”,p+1);

printf(“%p\n”,a+2);

printf(“%p\n”,&a[2]);

printf(“%p\n”,p+2);

printf(“%d\n”,*a);

printf(“%d\n”,*(a +1));

printf(“%d\n”,*(a+2));

用指针遍历数组

for(int i= 0;i < 5;i++){

printf(“%d\n”,*(a+i));

}

定义指针变量访问数组中的元素

int *p =NULL;

p = a;

printf(“%p\n”,a);

printf(“%p\n”,p);

printf(“%d\n”,*p);

printf(“%d\n”,*(p+1));

printf(“%d\n”,*(p+2));

练习

有10个元素的数组,通过指针变量为元素随机赋值[22 33]

7.数组名(数组元素的首地址)   与指向数组首地址的指针变量的区别:

a. 数组名(数组首地址) 是一个常量地址不能被修改

a = NULL;error

指针变量可以修改,可以重指向

b. 数组名(数组的首地址),用sizeof 计算得到的结果,整个数组所占的字节数,而用 sizeof 计算指向数组元素首地址的指针变量得到是一个定值4或者8

printf(“%lu\ n”,sizeof(c));

//定义一个10个元素的数组,通过指针变量为元素随机赋值[22 33],冒泡排序;

8.指针在字符串中的应用

用% s 打印是从指针指向那个地址开始向后输出

char string[] = “Canglaoshi”;

printf(“%s\n”,string);

printf(“%s\n”,string+1);

通过指针访问里面的元素

数组名(数组元素的首地址)  == 指针

*(string + 3) = ‘\0'

printf(“%s\ n”,string);

通过指针访问元素

printf(“%c\ n”,*(string +3));

通过指针计算字符串的长度

int i= 0;

*(string +i)  取到数组中对应位置的值

while(*(string+i) != ‘\0’){//string[i]

i++;

}

printf(“%d\n”,i);

指针变量一定要和指向的数据类型相同

char *p = string;

int i = 0;

while(*(p+i) != ‘\0’){

i++;

}

char string[] = "canglaoshi I love you";//将字符串的首个字母大写,并且将空格换成下划线

char string[] = "canglaoshi I love you";

*string -= 32;

char *p = string;

if (string[0] >= 'a' && string[0] <='z') {

string[0] -= 32;

}

int i = 0;

while (*(string+i) != '\0') {

if (*(string + i) == ' ') {

*(string + i) = '-';

}

i++;

}

printf("%s\n",string);

//写一个函数实现两变量的交换

int a = 10;

int b = 20;

change(&a,&b);

printf("a = %d,b = %d\n",a,b); int a = 10,b = 20; int sum = 0,sub = 0;

sum = sumAndsub(a,b,&sub); printf("sum = %d,sub = %d\n",sum,sub); float a[10] = {0}; for (int i = 0; i < 10; i++) {

*(a+i) =arc4random()%21+10;

printf("%.2f ",*(a+i));

} printf("\n"); for (int i = 0; i < 10 - 1; i++) { for (int j = 0; j < 10 - i - 1;j++) {//            if (a[j] > a[j + 1]) {//                float temp = 0;//                temp = a[j];//                a[j] = a[j + 1];//                a[j + 1] = temp;//            } if (*(a + j) > *(a + 1 + j)) { float temp = 0;

temp = *(a +j);

*(a + j) = *(a + j + 1);

*(a + j + 1) = temp;

}

}

} printf("\n"); for (int i = 0; i < 10; i++) {

printf("%.2f ",*(a+i));

}

结构体指针

1.形参和实参的区别

a. 形参:定义的时候写的参数,(起一个描述的作用,没有实际的意义)

b. 实参:函数实际调用时传进来的参数

形参和实参的传递是单向的.

2.结构体嵌套

在定义结构体的时候,结构体的成员变量也可以是结构体.

3.结构体指针

指向结构体的指针叫结构体指针.

数据类型  + *  + 变量名 + 初始值;

Student  stu1 = {“lisi”,’M’,29};

指针变量指向结构体变量的首地址,相当于指向结构体第一个成员变量的地址

Student *p = &stu1;

结构体指针的访问

printf(“%s”,(*p).name);

通过指针变量访问结构体变量的成员

printf(“%s,%c,%d\n”,p->name,p->sex,p->age);

4——>:指向操作符

只有定义的是结构体变量的首地址,才可以使用(—>指向操作符)访问结构体变量

printf(“%s,%c,%d\n”,p->name,p->sex,p->age);

5.float x1 = 0.1;

float x2 = 1.;

float x3 = 1.f;

float x4 =1.0f;

float x5 = 1;

6.结构体数组与指针的关系

结构体数组的数组名是一个结构体指针常量.

int a[5] = {1,2,3,4,5};

int *p = a;//数组名就是数组的首地址.

printf(“%d\n”,*p);

*stu   :   stu[0]  //代表的都是数组中第一个元素,

*(stu + 1) :stu[1]  // 代表的都是数组中的第二个元素.

*(stu + 2)   :stu[2]  //代表的是数组中的第三个元素.

访问数组中结构体元素的属性

*stu.name   :stu[0].name

(*(stu + 1)).name  :  stu[1].name

—>:指向操作符  :使用的时候一定要保证指针指向结构体变量的首地址

stu—> name   :stu[0].name

(stu + 1) —>name  :stu[1].name

(stu + 2)——>name   : stu[2].name

7.遍历结构体数组的时候,需要向函数中传入数组和长度.

8.指针数组(也就是指向指针的指针)

int  a = 3,b = 4,c=  5;

数组中的元素都是指针(地址)数组,就是指针数组.

int *array[3] = {&a,&b,&c};//3*8个字节

printf(“%p\n”,array[0]);

printf(“%p\n”,&a);

printf(“%d\n”,**array);//*array  取到地址  **array  取到地址里的值

printf(“%d\ n”,*(*(arrary + 1)));

二.函数指针

函数指针的声明方法为:

函数类型  (标示符  指针变量名 )(形参列表);

函数类型说明函数的返回类型,”(标识符 指针变量)”中的括号不能省,若省略整体则成为一个函数说明,说明了一个返回的数据类型是指针的函数,后面的”形参列表"表示指针变量指向的函数所带来的参数列表.

例如:

int func(int x); 声明一个函数

int (*f)(int x);

函数指针

1.函数指针类型的确定步骤

1⃣把函数名换成(*)    void (*)()    int(*)(int,int)

2⃣如果有参数,把参数名去掉,只保留参数类型  void (*)()   int (*)(int,int)

3⃣格式

指针类型  *指针名  = 初始值;

char *p = NULL;

函数指针的类型

返回值类型(*函数指针变量名)(参数类型1,参数类型2.....) = 初始值;

函数后面的()是函数调用符.

注意:  函数指针变量名不能和指针重名

int sum(int a,int b){

return a+b;

}

int (*Sum)(int,int);

Sum = sum;

int y = Sum(3,5);

printf(“%d\n”,y);

同一个函数指针可以指向不同的函数,但是(前提是:函数指针的类型必须一致)

2.typedef 原始类型  新类型;

给函数指针类型起别名

typedef int (*FUN)(int,int);

typedef void (*HELLO)

typedef  返回值类型(*新类型名)(参数类型1,参数类型2.....)

3.函数回调

函数回调:就是用函数指针来调用函数

函数名就是指针,存放的函数的首地址

4.动态排序

就是不断的改变排序的条件,根据不同的条件,调用不同的函数,进行排序.

5.枚举

定义:一组有符号的整形常量,一一列举所有的状态,罗列出所有可能的结果

enum season {

spring,

summer,

autumn,

winter};

printf(“%d\n”,spring);

枚举经常和 swith 合用

枚举间接提高了代码的可读性

将人能识别的表示符,与计算机能识别的数字建立联系

6.宏只做简单的替换,在预编译的时候完成替换

宏命名规范:

1⃣纯大写

2⃣k +  大驼峰

无参宏直接进行定义,有参宏可以使用常量表达式

#define SUM(A,B)  ((A) - (B)) // 最安全的方式

有参数的宏,只做简单的替换运算,不会判断运算符的优先级

int p = SUM(3 + 7,5 + 6) * 3;//3 + 7 * 5 + 6

7.条件编译

第一种

#ifdef  MY

printf(“Hello Word!!");

#else

printf(“明天考试!!");

#endif

特点:如果标示符被# define 过,就会执行代码段1,否则就会执行代码段2

第二种方式

#ifndef  标示符

代码段1

#else

代码段2

#endif

特点:如果标示符没有被#define过,就会执行代码段1;如果被定义过,,就编译代码段2

第三种方式

#if  常量表达式

代码段1

#else

代码段2

#endif

#if MY

printf(“你好蓝欧!!");

#else

printf(“你好中国!!");

#endif

特点:如果常量表达式非0,就执行代码段1,否则执行代码段2

8.const 常量修饰符

被 const修饰的常量是不能重新赋值的

c语言把结构体首地址放入指针,C语言基础———指针,结构体指针,函数指针相关推荐

  1. 通过结构体某个成员的地址计算结构体首地址 (转)

    最近在CU论坛上有很多人在问这样一个问题:给出一个结构体成员的地址计算该结构体的起始地址.其实这个题我之前也没有接触过,据说内核代码中有这样用的,但还没有看到.不过觉得这个题的解决方法还是有一定技巧的 ...

  2. 通过结构体某个成员的地址计算结构体首地址

    给出一个结构体成员的地址计算该结构体的起始地址,据说内核代码中有这样用的,但还没有看到.不过觉得这个题的解决方法还是有一定技巧的,就总结一下.下面是实现的代码. /* Author: Godbach ...

  3. 结构体第一个成员是结构体,则为父结构体首地址demo(六)

    //1.完整版 #include <stdio.h> #include <stdlib.h> struct audio_stream_in {ssize_t (*read)(s ...

  4. 宏定义来实现一个结构体成员相对于该结构体首地址的偏移量

    #define my_offerset(type , exp) ((int)&(((type*)0)->exp))//因为是求结构体的成员内存偏移.结构体会定义一种新的数据类型 所以ty ...

  5. c语言将0到1十等分放入数组,C语言课程设题计目汇总.doc

    C语言课程设题计目汇总 目录 杨顺民题目1 题目1:年历显示1 题目2:小学生测验1 题目3 运动会比赛计分系统2 题目4:学生学籍管理系统(限2人)2 题目5:排班系统2 题目6:通讯录程序设计(限 ...

  6. 二进制转换为十进制c语言编程,将二进制IP地址转换成十进制(C语言程序实现)

    将二进制IP地址转换成十进制(C语言程序实现) /* * Name: IP Address * Funcion: To convert binary numbers to decimal number ...

  7. java把map值放入vector_Thinking in java基础之集合框架

    Thinking in java基础之集合框架 大家都知道我的习惯,先上图说话. 集合简介(容器) 把具有相同性质的一类东西,汇聚成一个整体,就可以称为集合,例如这里有20个苹果,我们把每一个苹果当成 ...

  8. 结构体中元素的偏移地址与首地址

    结构体中元素的偏移地址与首地址 1.offsetof() 0指针的使用 2.container_of() 1.offsetof() #define offsetof(TYPE, MEMBER) ((s ...

  9. c 定义结构体时提示应输入声明_C语言结构体的坑很多,这6大方法千万要记住!...

    本文福利在文末! C语言可谓是编程界的传奇语言,历经几十年,依然排名前列. 本文主要说的是C语言中的结构体,结构体是C语言中重要的一部分内容,也是C语言中常用的一种数据结构. 一.关于结构体在C语言中 ...

最新文章

  1. SCA与spring集成(在spring中开发SOA)
  2. python趣味编程10例-Python趣味编程与精彩实例,码高少儿编程 编
  3. Jenkins 管理界面里提示“反向代理设置有误“的问题解决办法
  4. Zookeeper_简介
  5. 内核态和用户态的区别
  6. 深入剖析阿里云推荐引擎——新架构,新体验
  7. android 引用非 android 工程,Unity3D调用android方法(非插件方式)
  8. 【BZOJ2038】小Z的袜子,第一次的莫队算法
  9. 鸿蒙硬件HI3861-I2C-MCP23017
  10. Windows Server 2003 SP2中文版开放下载
  11. Linux 系统镜像打包流程
  12. 用英雄联盟的方式讲解 JavaScript 设计模式
  13. 香港各个大学计算机类专业
  14. 网络安全 (九 缓冲区溢出metasploit)
  15. php怎么插入画笔,ps画笔怎么设置
  16. C# VBA 提取word中图片方法
  17. pdfminer __init__() got an unexpected keyword argument ‘codec‘解决方案
  18. 微软正式发布Chromium Edge开发预览版
  19. JAVA实现简易的酒店管理系统
  20. <LeetCode天梯>Day004 买卖股票的最佳时机 II(DP动态规划法) | 初级算法 | Python

热门文章

  1. Python+Django+Mysql实现在线电影推荐系统 基于用户、项目的协同过滤推荐在线电影系统 代码实现 源代码下载
  2. QQ在线客服JS代码,自适应漂浮在网页右侧
  3. Java实现 蓝桥杯 算法提高 快乐司机
  4. 什么是low-level、high-level任务
  5. humanoid ik unity 配件 animation的问题
  6. [Linux驱动炼成记] 11-快速修改芯片驱动中寄存器的值
  7. 在C或C++中如何使用PI(π)值
  8. 《炬丰科技-半导体工艺》 组合式 CMP 和晶片清洗装置方法
  9. 微信接口验证类php,微信公众平台消息接口校验与消息接口响应实例
  10. 0x01A686F0 处有未经处理的异常(在 五金上色软件.exe 中): 0xC000041D: 用户回调期间遇到未经处理的异常。。...