指针是什么

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

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

相关运算符

【&】在变量中取地址

【*】在地址中取变量

测试小程序:

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

指针变量的类型

》》指针类型: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)。

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

指针变量作为函数参数

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

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

数组作为函数参数

#include<stdio.h>
void fun1(int *arr){
arr[]=;
arr[]=;
}
void fun2(int arr[]){
arr[]=;
arr[]=;
}
void main(){
//变量初始化
int i;
int a[]={,,,,,,};
//函数调用
fun1(a);
fun2(a);
//打印
for(i=;i<sizeof(a)/sizeof(int);i++){
printf("%d ",a[i]); //10 11 100 110 4 5 6
}
}

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

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

 #include<stdio.h>

 void fun1(int *p){
printf("%d",p[]);//
}
void fun2(int p[]){
printf("%d",p[]);//
} void fun3(int p[]){
printf("%d",p[]);//
} void fun4(char *p[]){
printf("%s",p[]);//dong
} void fun5(char **p){
printf("%s",p[]);//dong
} void main(){
int ii[]={,,};
fun1(ii);
fun2(ii);
fun3(ii);
char *ch[]={"dong","xiao"};
fun4(ch);
fun5(ch);
}

一维数组指针变量

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

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

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

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

函数数组参数

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

二维数组指针变量

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

指针引用字符串

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

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

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

可变格式的输出函数:

#include<stdio.h>
void main() {
char *ch = "dong xiao %d\n";
printf(ch, );
ch = "xiaoxiao%d\n";
printf(ch, );
char chh[] = "dongdong %d\n";
printf(ch, );
}

指向函数的指针

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

返回值为int

#include<stdio.h>
void main() {
int minto(int a, int b);//函数声明
int(*p)(int, int);//定义一个函数指针变量p
p = minto;//函数指针指向函数minto首地址
int cc = (*p)(, );//调用函数
printf("Min===%d", cc);
} int minto(int a, int b) {
if(a > b) return b;
else return a;
}

无返回值:

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

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

#include<stdio.h>
void main() {
int fun(int(*addpp)(int, int), int x, int y);//函数声明
int add(int i, int j); int ii=fun(add, , );//传递函数名和参数即可
printf("输出相加的值为:%d", ii);
} //int (*addpp)(int,int);addpp=add;
int fun(int (*addpp)(int,int),int x,int y){
int cc = (*addpp)(x, y);
return cc;
} int add(int i, int j) {
return i + j;
}

返回指针的函数

#include<stdio.h>
void main() {
int* add(int i, int j);
int *p = add(, );
printf("输出相加的值为:%d", *p);
} int* add(int i, int j) {
int aa = i + j;
return &aa;//返回地址
}

指针数组

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

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

进阶版

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

void类型指针

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

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

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

#include<stdio.h>

void fun1(void *i){
int *p=(int *)i;//强制类型转换
*p=;
} void main(){
int ii=;
fun1(&ii);
printf("%d",ii);//输出100
}

错误示范

1、

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

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

2、

int f = 12.3;
int *p;
*p = &f; //错误1
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. day17-jdbc 8.ResultSet介绍

    但是这些东西在mysql那里有问题.mysql的驱动不是很完善.getClob().getBlob()不好使不是因为程序的问题,而是因为mysql驱动的问题,oracle驱动就没有这个问题,证明ora ...

  2. GSON 报错HibernateProxy. Forgot to register a type adapter? 的解决办法

    使用Gson转换hibernate对象遇到一个问题,当对象的Lazy加载的,就会出现上面的错误.处理方式摘抄自网上,留存一份以后自己看. 网上找到的解决办法,首先自定义一个类继承TypeAdapter ...

  3. HDU 4348(主席树 标记永久化)

    题面一看就是裸的数据结构题,而且一看就知道是主席树... 一共四种操作:1:把区间[l, r]的数都加上d,并且更新时间.2:查询当前时间的区间和.3:查询历史时间的区间和.4:时光倒流到某个时间. ...

  4. Linux如何修改网络环境参数

    如下设置: 检验是否可以连通,就使用ping命令ping 网关开始的时候总是现实unreachable 设置IP:sudo ifconfig eth0 133.133.133.190 netmask ...

  5. 正割、余割、正弦、余弦、正切、余切之间的关系的公式 sec、csc与sin、cos、tan、cot之间的各种公式

    1.倒数关系 tanα ·cotα=1 sinα ·cscα=1 cosα ·secα=1 2.商数关系 tanα=sinα/cosα cotα=cosα/sinα 3.平方关系 sinα²+cosα ...

  6. Ryouko's Memory Note

    题目意思:一个书有 n 页,每页的编号依次从 1 到 n 编排.如果从页 x 翻到页 y,那么|x-y|页都需要翻到(联系生活实际就很容易理解的了).接着有m pieces 的 information ...

  7. Spring JDBCTemplate配置使用

    一.开发环境 Windows 10 IntelliJ IDEA 2016.1 旗舰版 JDK1.8 二.项目和数据库结构 项目结构: 数据库(MySQL 5.5.39): /* Navicat MyS ...

  8. Java 接口实际应用代码

    package interfaceDemo; interface Equipment_specifications{ void DoWork(); } class MBorad{//主板 privat ...

  9. Spring-访问静态资源文件的方法

    转自:  http://blog.163.com/zhangmihuo_2007/blog/static/27011075201453044959574?suggestedreading 如果你的Di ...

  10. 用create table 命令建立表

    create table [[V.]HANKE.].MADE IN HOME (xuliehao int primary key, name varchar(20)not null, jiage fl ...