指针是什么

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

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

相关运算符

【&】在变量中取地址

【*】在地址中取变量

测试小程序:

#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. 第4章 springboot热部署 4-1 SpringBoot 使用devtools进行热部署

    /imooc-springboot-starter/src/main/resources/application.properties #关闭缓存, 即时刷新 #spring.freemarker.c ...

  2. 面试题:hibernate 第二天 快照 session oid 有用

    ## Hibernate第二天 ## ### 回顾与反馈 ### Hibernate第一天 1)一种思想 : ORM OM(数据库表与实体类之间的映射) RM 2)一个项目 : CRM 客户关系管理系 ...

  3. BuilderPattern(23种设计模式之一)

    设计模式六大原则(1):单一职责原则 设计模式六大原则(2):里氏替换原则 设计模式六大原则(3):依赖倒置原则 设计模式六大原则(4):接口隔离原则 设计模式六大原则(5):迪米特法则 设计模式六大 ...

  4. Entity Framework Tutorial Basics(30):

    CRUD using Stored Procedure: In the previous chapter, we have seen how to get data using a stored pr ...

  5. WordCount 编码与测试

    word count github 项目地址:https://github.com/liuqiang666/wordCount PSP表格 PSP2.1  PSP阶段  预估耗时(小时)  实际耗时( ...

  6. [转]关于截取字符串substr和substring两者的区别

    subString(start,stop) substr(start,length) substr和substring两个都是截取字符串的. 两者有相同点,如果只是写一个参数,两者的作用都是一样的:就 ...

  7. winform ComBox绑定数据

    初始化数据: List<KeyValuePair<string, string>> list: ComBox1.ValueMember = "Key";Co ...

  8. jQuery的选择器+实例

    返回目录 jQuery的冒号选择器 表单  :input :text :password :radio :checkbox :submit :image :reset :button :file :h ...

  9. HBase - 安装过程中的问题

    问题1:启动时start-hbase.sh 报 权限不够 原因:在移动文件时,使用root用户在/usr/local下创建的hbase,所以hbase文件夹的使用者为root,其他人没权限 解决方案: ...

  10. 「BZOJ 3994」「SDOI 2015」约数个数和「莫比乌斯反演」

    题意 设\(d(x)\)为\(x\)的约数个数,求\(\sum_{i=1}^{n}\sum_{j=1}^{m}d(ij)\). 题解 首先证个公式: \[d(ij) = \sum_{x|i}\sum_ ...