C语言——指针
·
一、什么是指针
指针表示内存地址(如酒店的房间号表示房间的地址)
我们平时说的指针,是保存地址的指针变量
二、定义指针变量
2.1 格式
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a,b,c;
printf("%p\t%p\t%p\n",&a,&b,&c);
//使用指针变量保存a的地址
int *p = &a;
printf("p=%p\n",p);
//因为指针变量p的值就是内存地址,所以使用%p格式符打印
return 0;
}
2.2 指针的初始化和赋值
指针和变量的关系
指针指向一个变量实际上是指向该变量的首地址

#include <stdio.h>
int main(int argc, const char *argv[])
{
int *p; //定义了一个能够保存一个int类型变量地址的指针p
//上面的p现在是一个野指针(不知道指向的指针)
int a=90;
//用int类型变量a的地址给指针p赋值
//让指针p指向变量a
p = &a;
/*******************通过指针访问变量的值***********************/
//拿到变量的地址后,需要对地址解引用访问到地址中的内容
//可以使用(*地址)解引用
printf("%d\n",*p);
*p = 12; //<==>a=12
printf("a=%d\n",a);
//定义指针p1并初始化
int *p1 = NULL; //NULL表示空地址,当指针没有明确指向时可以指向NULL
return 0;
}
2.3 通过指针的间接访问
直接通过变量名访问变量是直接访问
通过变量的地址(指针)访问变量是间接访问
如何通过指针访问变量:对地址进行解引用(对地址取*)
总结 * 的用法:
1、定义时,表示定义了指针变量
2、解引用时,表示取地址中的内容
PS:如果*前面有数据类型一定是定义指针变量, 如果*前面没有数据类型一定是对地址的解引用
#include <stdio.h>
int main(int argc, const char *argv[])
{
int *p; //定义了一个能够保存一个int类型变量地址的指针p
//上面的p现在是一个野指针(不知道指向的指针)
int a=90;
//用int类型变量a的地址给指针p赋值
//让指针p指向变量a
p = &a;
//定义指针p1并初始化
int *p1 = NULL; //NULL表示空地址,当指针没有明确指向时可以指向NULL
/*******************通过指针访问变量的值***********************/
//拿到变量的地址后,需要对地址解引用访问到地址中的内容
//可以使用(*地址)解引用
printf("%d\n",*p);
*p = 12; //<==>a=12
printf("a=%d\n",a);
return 0;
}
2.4 指针的运算
因为指针是一个内存地址,对于指针的大部分运算没有实际意义。
指针常用的操作是加法和减法
#include <stdio.h>
int main(int argc, const char *argv[])
{
int *p; //定义了一个能够保存一个int类型变量地址的指针p
//上面的p现在是一个野指针(不知道指向的指针)
int a=90;
//用int类型变量a的地址给指针p赋值
//让指针p指向变量a
p = &a;
printf("p=%p\n",p); //0x3c
printf("p+1=%p\n",p+1); //0x40,相差四个字节 p+1表示p所指向空间的下一个位置
printf("++p=%p\n",++p); //++p表示指针变量p本身向后偏移一个字节
char c;
char *p1=&c;
printf("p1=%p\n",p1); //0x73
printf("p1+1=%p\n",p1+1); //0x74,相差四个字节
return 0;
}
PS:
指针的加减运算,表示向后或者向前偏移n个字节。
n由指针的数据类型决定。
2.5 指针的大小
指针的大小和数据类型无关,指针的数据类型只决定指针的偏移量
指针的大小由操作系统决定,32位操作系统占4Byte,64位操作系统占8Byte。
2.6 指针和一维整形数组
数组的特点:数组名表示数组的首地址
所以指针指向一维数组,可以直接将数组名赋值给指针

#include <stdio.h>
int main(int argc, const char *argv[])
{
int arr[4]={1,9,34,2};
/****定义指针p指向一维整形数组****/
int *p = arr; //数组名本身就是数组的首地址
//p = &arr[0];
printf("%d\n",*p); //*p<==>arr[0]
//p<==>arr
//arr[i]<==>*(p+i)
//p[i]<==>arr[i]
//*(p+i)<==>*(arr+i)
//p+i<==>arr+i
//[i]<==>对地址先偏移i个字节,再解引用(取*)
printf("p+1=%p\t*(p+1)=%d\n",p+1,*(p+1)); //<==>arr[1]
printf("arr+2=%p\t*(arr+2)=%d\n",arr+2,*(arr+2)); //<==>arr[2]
printf("p+3=%p\t*(p+3)=%d\n",p+3,*(p+3)); //<==>arr[3]
return 0;
}
#include <stdio.h>
int main(int argc, const char *argv[])
{
int arr[5]={12,8,59,61,70};
int *p=arr;
printf("%p\n",arr);
printf("%p\n",arr+3);
//printf("%p\n",p+5); 越界访问,因为数组中只有5个元素
printf("%d\n",*(p+1)); //8
printf("%d\n",*p+2); //14
printf("%d\n",p[3]); //<==>*(p+3) 61
return 0;
}
2.6.1 练习
2.6.1.1 用指针的形式,完成对数组中元素的输入和输出

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
int arr[5];
int *p=arr;
int i;
for(i=0;i<5;i++)
{
scanf("%d",p+i);
}
for(i=0;i<5;i++)
{
printf("%d ",*(p+i));
}
printf("\n");
return 0;
}
2.6.1.2 通过指针,求数组中元素的最大值

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
int arr[6]={231,195,632,456,245,654};
int *p=arr;
int max=*p;
int i;
for(i=1;i<6;i++)
{
if(*(p+i)>max)
{
max=*(p+i);
}
}
printf("max=%d\n",max);
return 0;
}
2.6.1.3 定义一个数组,用指针指向该数组并用指针的形式完成冒泡排序。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
int arr[6]={156,324,126,489,456,354};
int *p=arr;
int i,j,temp;
for(i=0;i<6;i++)
{
for(j=0;j<5;j++)
{
if(*(p+j)>*(p+j+1))
{
temp=*(p+j);
*(p+j)=*(p+j+1);
*(p+j+1)=temp;
}
}
}
for(i=0;i<6;i++)
{
printf("%d ",*(p+i));
}
printf("\n");
return 0;
}
2.6.1.4 使用指针,实现数组的逆置

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
int arr[]={1,2,3,4,5,6};
int *p=arr;
int len=sizeof(arr)/sizeof(arr[0]);
int i,j,temp;
i=0;
while(i<len/2)
{
temp=*(p+i);
*(p+i)=*(p+len-1-i);
*(p+len-1-i)=temp;
i++;
}
for(i=0;i<len;i++)
{
printf("%d ",*(p+i));
}
printf("\n");
return 0;
}
2.7 指针和一维字符数组
本质上与指针指向以为整型数组一致,只有数据类型不同
char str[100]="hello";
char *p = str;
str[i]<==>p[i]
*(str+i)<==>*(p+i)
str+i<==>p+i
#include <stdio.h>
int main(int argc, const char *argv[])
{
char str[100]="hello";
char *p = str;
printf("str=%p\n",str);
printf("str+1=%p\n",str+1);
printf("p=%p\n",p);
printf("p+1=%p\n",p+1);
return 0;
}
2.7.1 练习
2.7.1.1 终端输入字符串,如果有大写字母转为小写字母,如果是小写字母转为大写字母,其他字符转为#

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
char str[100];
gets(str);
printf("str=");
puts(str);
char *p=str;
while(*p!='\0')
{
if(*p>'A'&&*p<'Z')
{
*p+=32;
}
else if(*p>'a'&&*p<'z')
{
*p-=32;
}
else
{
*p='#';
}
p++;
}
printf("str=");
puts(str);
return 0;
}
2.7.1.2 使用指针实现字符串函数族的函数:strlen、strcpy、strcat、strcmp
strlen:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
char str[]="hello";
char *p=str;
int count=0;
while(*p!='\0')
{
count++;
p++;
}
printf("len=%d\n",count);
return 0;
}
strcpy:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
/*******strcpy*********/
char str1[100]="hello";
char str2[100]="hi";
printf("str1=");
puts(str1);
char *p1,*p2;
p1=str1;
p2=str2;
while(*p1!='\0'||*p2!='\0')
{
*p1=*p2;
p1++;
p2++;
}
*p1='\0';
printf("str1=");
puts(str1);
return 0;
}
strcat:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
/*******strcat********/
char str1[100]="hello";
char str2[100]=" wu yi fan";
printf("str1=");
puts(str1);
printf("str2=");
puts(str2);
char *p1,*p2;
p1=str1;
p2=str2;
while(*p1!='\0')
{
p1++;
}
while(*p2!='\0')
{
*p1=*p2;
p1++;
p2++;
}
*p1='\0';
printf("str1=");
puts(str1);
return 0;
}
strcmp:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
/*******strcmp*********/
char str1[100]="hello";
char str2[100]="hi";
char *p1,*p2;
p1=str1;
p2=str2;
while(*p1==*p2&&*p1!='\0')
{
p1++;
p2++;
}
printf("str1与str2从第一位开始首个不同元素的ASCII码差值为:\n%d\n",*p1-*p2);
return 0;
}
三、内存分区
栈区:定义变量时,自动申请自动释放
堆区:程序手动申请,手动释放
静态区:用static修饰的关键字都在静态区

PS:指针指向字符串常量区的内容,不能通过指针修改
#include <stdio.h>
int main(int argc, const char *argv[])
{
char *p="hello world";
//定义了一个char类型的指针变量p,指向字符串常量hello world
//根据内存分区,字符串常量被分配在.ro段
//该分区中的内容不能更改,为只读内容
//*p = 'a';
printf("1\n");
p=NULL; //让指针p指向NULL
printf("%c\n",*p); //段错误
return 0;
}
四、段错误
本质:非法访问内存
1.修改常量区的内容
2.野指针的间接访问(错误不能预知)
3.数组越界(错误不能预知)
4.空指针的间接访问
五、练习
5.1输入带空格的字符串,删除字符串中的空格

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
char str[100];
gets(str);
char *p=str;
while(*p!='\0')
{
if(*p==' ')
{
while(*p!='\0')
{
*p=*(p+1);
p++;
}
p=str;
}
p++;
}
puts(str);
return 0;
}
更多推荐




所有评论(0)