一、没有目标的指针(野指针),如:
int *p;
printf("p= %p\n",p);
野指针的危害:
1、指向操作系统的内核区,禁止访问;
2、指向一个没有使用的内存,指针解引用合法;
3、指向一个可用地址,但是此刻被其他的程序所使用,会引发错误(能运行,但导致结果错误)
二、const修饰作用:修饰的是就近原则,修饰就近的一个类型
1、const int *p1; int *p1里面的变量包括有 p1和p1指向的变量(int),隐含变量
const修饰的是int所包含的隐含变量
2、int const *p2;
修饰的也是p2指向的隐含变量
3、int * const p3;
修饰的是p3;
4、输出型参数:调用函数,改变内存中的值
void func(int *p)
{
*p = 33;
}
int main(void)
{
int n = 1;
printf("n in yuanshi%p.\n",&n);
printf("%d.\n",n);
int *p_n = &n;
func(p_n);
printf("%d.\n",n);
printf("n in func%p",&n);
return 0;
}
5、输入型参数:const修饰的变量
6、传值调用:运用的是地址的唯一性!!实质还是传值调用,只不过是地址罢了
#include<stdio.h>
void swap(int *a, int *b)
{
int temp = 0;
temp = *a;//*a访问的是x里面的内容
*a = *b;
*b = temp;
}
int main(void)
{
int x = 33, y = 44;
printf("x = %d y = %d.\n",x,y);
swap(&x, &y);
printf("x = %d y = %d.\n",x,y);
return 0;
}
三、宏定义:定义常量
1、 预编译时(展开头文件,去掉所有注释,宏替换),就替换了所使用的代码位置数据。
仅仅是替换!不进行任何的运算
#include<stdio.h>
#define N 5+1
#define M N*N
//三目运算符
#define MAX(a,b) (a) > (b) ? (a) : (b)
int main(void)
{
int i = N;
printf("i = %d.\n", i);
int ret = M; //M = 5+1*5+1==11
printf("%d.\n",M);
int max = MAX(4,7);
printf("%d.\n",max);
return 0;
}
define DPINT int* 第一个类型是int*型(指针),第二个是int型!所有变量的类型都是唯一的!
#include<stdio.h>
#define DPINT int*
int main(void)
{
int num = 1;
DPINT p1, p2;
p1 = #
p2 = num;
printf("%d",p1);
printf("%d",p2);
return 0;
}
2、发生在编译阶段typedef int* ttt;//ttt是这种类型的新名字! ttt p1,p2;两个类型都是int*型的
#include<stdio.h>
typedef int* ttt;
int main(void)
{
int num = 1;
ttt p1,p2;
p1 = #
p2 = #
return 0;
}
数组里面的指针
左值和右值:arr只能作为右值,不能做左值,所占的字节不一样。
数组名作为右值是一个地址变量,*arr表示的是数组首元素首地址;
#include<stdio.h>
int main(void)
{
int arr[5] = {1,3,5,7,9}, i =0;
// printf("&arr[0]= %p\n",&arr[0]);
// printf("arr = %p.\n",arr);
for(i=0;i<5;i++)
{ //i每加1次,指针偏移4个字节 sizeof(int(指针所指向的类型))*i
printf("arr[%d] = %d.\n",i, *(arr+i));
}
int *p = NULL;
p = arr;
for(i=0;i<5;i++)
{
printf("arr[%d] = %d.\n",i, *p);
p++;
}
return 0;
}
同一数组的不同元素指针,相减之后就是下标的差值
p = &arr[2];
int *q = &arr[4];
int ret = q-p;
printf("ret %d.\n",ret);//ret =4-2=2;
数组里面的指针和运算符的结合
前置++:
#include<stdio.h>
int main(void)
{
int arr[5] = {1,3,5,7,9}, i =0;
int *p = arr;
//后置++,先进行复制运算,指针停留在arr[0]的首地址,赋值完成之后,进行++,指针指向位置为[1]
// printf("*p++= %d.\n",*p++);//1
// printf("*p=%d.\n",*p);//3
printf("*(p++)= %d.\n",*(p++));//1 不会因为加了括号就先进行括号的自加运算,还是先和左边*做运算(语句运算完了之后才能进行自加)
printf("*p=%d.\n",*p);//3
return 0;
}
后置++:
#include<stdio.h>
int main(void)
{
int arr[5] = {1,3,5,7,9}, i =0;
int *p = arr;
printf("*++p = %d.\n",*++p);//3
printf("*p=%d.\n",*p);//3
return 0;
}
前置++*p
#include<stdio.h>
int main(void)
{
int arr[5] = {1,3,5,7,9}, i =0;
int *p = arr;
//*p(arr[0]=*p(arr[0])+1),数组元素发生变化
printf("++*p = %d.\n",++*p);//2
//数组元素的指针没有移动,只是修改了值,还是指向arr[0];
printf("*p=%d.\n",*p);//2
return 0;
}
sizeof(int [5])*1==偏移地址偏移量
#include<stdio.h>
int main(void)
{
//&arr+1偏移了整个数组的字节数 20个字节
int arr[5] = {1,3,5,7,9}, i =0;
int *p = arr;
// printf("&arr =%p.\n",&arr);
// printf("&arr+1 = %p.\n",&arr+1);
printf("%d.\n",sizeof(int [5]));
return 0;
}
指针与字符串:
偏移量是sizeof(char)*2
#include<stdio.h>
int main(void)
{
char buf[]="1234567";
// printf("buf=[%s].\n",buf);
*buf = 'a';
printf("buf=[%s].\n",buf);
printf("%d.\n",sizeof(*buf));
char ch=*(buf+2);
printf("%c.\n",ch);
return 0;
}
所有的字符串都是以“字符数组的形式存储在内存中”,提供一个起始地址,结束标志是'\0';
#include<stdio.h>
int main(void)
{
//指向的都是abc这个目标,而进行比较的是他们的地址,所以是一样的
char *str ="abc";
char *ptr = "abc";
if(str==ptr)
{
printf("zhengque");
}
else{
printf("cuowu");
}
return 0;
}
int *p;
printf("p= %p\n",p);
野指针的危害:
1、指向操作系统的内核区,禁止访问;
2、指向一个没有使用的内存,指针解引用合法;
3、指向一个可用地址,但是此刻被其他的程序所使用,会引发错误(能运行,但导致结果错误)
二、const修饰作用:修饰的是就近原则,修饰就近的一个类型
1、const int *p1; int *p1里面的变量包括有 p1和p1指向的变量(int),隐含变量
const修饰的是int所包含的隐含变量
2、int const *p2;
修饰的也是p2指向的隐含变量
3、int * const p3;
修饰的是p3;
4、输出型参数:调用函数,改变内存中的值
void func(int *p)
{
*p = 33;
}
int main(void)
{
int n = 1;
printf("n in yuanshi%p.\n",&n);
printf("%d.\n",n);
int *p_n = &n;
func(p_n);
printf("%d.\n",n);
printf("n in func%p",&n);
return 0;
}
5、输入型参数:const修饰的变量
6、传值调用:运用的是地址的唯一性!!实质还是传值调用,只不过是地址罢了
#include<stdio.h>
void swap(int *a, int *b)
{
int temp = 0;
temp = *a;//*a访问的是x里面的内容
*a = *b;
*b = temp;
}
int main(void)
{
int x = 33, y = 44;
printf("x = %d y = %d.\n",x,y);
swap(&x, &y);
printf("x = %d y = %d.\n",x,y);
return 0;
}
三、宏定义:定义常量
1、 预编译时(展开头文件,去掉所有注释,宏替换),就替换了所使用的代码位置数据。
仅仅是替换!不进行任何的运算
#include<stdio.h>
#define N 5+1
#define M N*N
//三目运算符
#define MAX(a,b) (a) > (b) ? (a) : (b)
int main(void)
{
int i = N;
printf("i = %d.\n", i);
int ret = M; //M = 5+1*5+1==11
printf("%d.\n",M);
int max = MAX(4,7);
printf("%d.\n",max);
return 0;
}
define DPINT int* 第一个类型是int*型(指针),第二个是int型!所有变量的类型都是唯一的!
#include<stdio.h>
#define DPINT int*
int main(void)
{
int num = 1;
DPINT p1, p2;
p1 = #
p2 = num;
printf("%d",p1);
printf("%d",p2);
return 0;
}
2、发生在编译阶段typedef int* ttt;//ttt是这种类型的新名字! ttt p1,p2;两个类型都是int*型的
#include<stdio.h>
typedef int* ttt;
int main(void)
{
int num = 1;
ttt p1,p2;
p1 = #
p2 = #
return 0;
}
数组里面的指针
左值和右值:arr只能作为右值,不能做左值,所占的字节不一样。
数组名作为右值是一个地址变量,*arr表示的是数组首元素首地址;
#include<stdio.h>
int main(void)
{
int arr[5] = {1,3,5,7,9}, i =0;
// printf("&arr[0]= %p\n",&arr[0]);
// printf("arr = %p.\n",arr);
for(i=0;i<5;i++)
{ //i每加1次,指针偏移4个字节 sizeof(int(指针所指向的类型))*i
printf("arr[%d] = %d.\n",i, *(arr+i));
}
int *p = NULL;
p = arr;
for(i=0;i<5;i++)
{
printf("arr[%d] = %d.\n",i, *p);
p++;
}
return 0;
}
同一数组的不同元素指针,相减之后就是下标的差值
p = &arr[2];
int *q = &arr[4];
int ret = q-p;
printf("ret %d.\n",ret);//ret =4-2=2;
数组里面的指针和运算符的结合
前置++:
#include<stdio.h>
int main(void)
{
int arr[5] = {1,3,5,7,9}, i =0;
int *p = arr;
//后置++,先进行复制运算,指针停留在arr[0]的首地址,赋值完成之后,进行++,指针指向位置为[1]
// printf("*p++= %d.\n",*p++);//1
// printf("*p=%d.\n",*p);//3
printf("*(p++)= %d.\n",*(p++));//1 不会因为加了括号就先进行括号的自加运算,还是先和左边*做运算(语句运算完了之后才能进行自加)
printf("*p=%d.\n",*p);//3
return 0;
}
后置++:
#include<stdio.h>
int main(void)
{
int arr[5] = {1,3,5,7,9}, i =0;
int *p = arr;
printf("*++p = %d.\n",*++p);//3
printf("*p=%d.\n",*p);//3
return 0;
}
前置++*p
#include<stdio.h>
int main(void)
{
int arr[5] = {1,3,5,7,9}, i =0;
int *p = arr;
//*p(arr[0]=*p(arr[0])+1),数组元素发生变化
printf("++*p = %d.\n",++*p);//2
//数组元素的指针没有移动,只是修改了值,还是指向arr[0];
printf("*p=%d.\n",*p);//2
return 0;
}
sizeof(int [5])*1==偏移地址偏移量
#include<stdio.h>
int main(void)
{
//&arr+1偏移了整个数组的字节数 20个字节
int arr[5] = {1,3,5,7,9}, i =0;
int *p = arr;
// printf("&arr =%p.\n",&arr);
// printf("&arr+1 = %p.\n",&arr+1);
printf("%d.\n",sizeof(int [5]));
return 0;
}
指针与字符串:
偏移量是sizeof(char)*2
#include<stdio.h>
int main(void)
{
char buf[]="1234567";
// printf("buf=[%s].\n",buf);
*buf = 'a';
printf("buf=[%s].\n",buf);
printf("%d.\n",sizeof(*buf));
char ch=*(buf+2);
printf("%c.\n",ch);
return 0;
}
所有的字符串都是以“字符数组的形式存储在内存中”,提供一个起始地址,结束标志是'\0';
#include<stdio.h>
int main(void)
{
//指向的都是abc这个目标,而进行比较的是他们的地址,所以是一样的
char *str ="abc";
char *ptr = "abc";
if(str==ptr)
{
printf("zhengque");
}
else{
printf("cuowu");
}
return 0;
}
本文详细探讨了C语言中的指针,包括野指针及其危害、const修饰符的作用、指针作为函数参数、宏定义的用法以及数组与指针的关系。通过实例解析了指针的前缀增量、后缀增量以及指针与字符串的操作,帮助读者深入理解C语言指针的本质。
1467

被折叠的 条评论
为什么被折叠?



