笔记
地址指向该变量单元,将地址形象化地称为“指针”。
在程序中一般是通过变量名来引用变量的值。
- 直接按变量名进行的访问,称为“直接访问”方式。
- “间接访问”的方式,即将变量的地址存放在另一变量(指针变量)中,然后通过该指针变量来找到对应变量的地址,从而访问变量。
指针定义:
类型名 *指针变量名;
左端的int是在定义指针变量时必须指定的**“基类型”。**
在定义指针变量时要注意:
- (1) 指针变量前面的“”表示该变量为指针型变量。指针变量名则不包含“”。
- (2)在定义指针变量时必须指定基类型。一个变量的指针的含义包括两个方面,一是以存储单元编号表示的纯地址(如编号为2000的字节),一是它指向的存储单元的数据类型(如int,char,float等)。
- (3) 如何表示指针类型。指向整型数据的指针类型表示为“int *”,读作“指向int的指针”或简称“int指针”。
- (4) 指针变量中只能存放地址(指针),不要将一个整数赋给一个指针变量。
int a, *p;
p=&a; //把a的地址赋给指针变量p
printf("%d",*p); //以整数形式输出指针变量p所指向的变量的值,即a的值
*p=1; //将整数1赋给p当前所指向的变量,由于p指向变量a,相当于把1赋给a,即a=1 ②
printf("%o",p); //以八进制形式输出指针变量p的值,由于p指向a,相当于输出a的地址,即&a ③
都可以存放在同一个指针变量中的,只有与指针变量的基类型相同的数据的地址才能存放在相应的指针变量中。
void *指针
是一种特殊的指针,不指向任何类型的数据。如果需要用此地址指向某类型的数据,应先对地址进行类型转换。
指针运算
① 指针变量加(减)一个整数。
p++; //将该指针变量的原值(是一个地址)和它指向的变量所占用的存储单元的字节数相加
② 指针变量赋值。将一个变量地址赋给一个指针变量。 不应把一个整数赋给指针变量。
p=&a; //将变量a的地址赋给p
p=array; //将数组array首元素地址赋给p
p=&array[i]; //将数组array第i个元素的地址赋给p
p=max; //max为已定义的函数,将max的入口地址赋给p
p1=p2; //p1和p2是基类型相同指针变量,将p2的值赋给p1
③ 两个指针变量可以相减。如果两个指针变量都指向同一个数组中的元素,则两个指针变量值之差是两个指针之间的元素个数。
④ 两个指针变量比较。若两个指针指向同一个数组的元素,则可以进行比较。指向前面的元素的指针变量“小于”指向后面元素的指针变量。如果p1和p2不指向同一数组则比较无意义。
通过指针引用数组
所谓数组元素的指针就是数组元素的地址。可以用一个指针变量指向一个数组元素。
int *p=&a[0]; == int *p=a;
用数组名作函数参数
int main()
{ void fun(int arr[], int n); //对fun函数的声明
int array[10]; //定义array数组
⋮
fun(array,10); //用数组名作函数的参数
return 0;
}
void fun(int arr[], int n) //定义fun函数
{
⋮
}
array是实参数组名,arr为形参数组名。当用数组名作参数时,如果形参数组中各元素的值发生变化,实参数组元素的值随之变化。
在该函数被调用时,系统会在fun函数中建立一个指针变量arr,用来存放从主调函数传递过来的实参数组首元素的地址
以变量名和数组名作为函数参数的比较
实参数组名代表一个固定的地址,或者说是指针常量,但形参数组名并不是一个固定的地址,而是按指针变量处理。
例题
【例8.2】
输入a和b两个整数,按先大后小的顺序输出a和b。
#include <stdio.h>
int main()
{ int *p1,*p2,*p,a,b; //p1,p2的类型是int *类型
printf("please enter two integer numbers:");
scanf("%d,%d",&a,&b); //输入两个整数
p1=&a; //使p1指向变量a
p2=&b; //使p2指向变量b
if(a<b) //如果a<b
{ p=p1;p1=p2;p2=p;} //使p1与p2的值互换
printf("a=%d,b=%d\n",a,b); //输出a,b
printf("max=%d,min=%d\n",*p1,*p2); //输出p1和p2所指向的变量的值
return 0;
}
a和b的值并未交换,它们仍保持原值,但p1和p2的值改变了。
实际上,第9行可以改为{p1=&b; p2=&a;}
即直接对p1和p2赋以新值,这样可以不必定义中间变量p,使程序更加简练。
【例8.6】
有一个整型数组a,有10个元素,要求输出数组中的全部元素
#include <stdio.h>
int main()
{ int a[10];
int *p,i;
printf("please enter 10 integer numbers:");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
for(p=a;p<(a+10);p++)
printf("%d ",*p);
//用指针指向当前的数组元素
printf("\n");
return 0;
}
【例8.3】
题目要求同例8.2,即对输入的两个整数按大小顺序输出。
现用函数处理,而且用指针类型的数据作函数参数。
#include <stdio.h>
int main()
{ void swap(int *p1,int *p2); //对swap函数的声明
int a,b;
int *pointer_1,*pointer_2; //定义两个int *型的指针变量
printf("please enter a and b:");
scanf("%d,%d",&a,&b); //输入两个整数
pointer_1=&a; //使pointer_1指向a
pointer_2=&b; //使pointer_2指向b
if(a<b) swap(pointer_1,pointer_2); //如果a<b,调用swap函数
printf("max=%d,min=%d\n",a,b); //输出结果
return 0;
}
void swap(int *p1,int *p2) //定义swap函数
{ int temp;
temp=*p1; //使*p1和*p2互换
*p1=*p2;
*p2=temp;
} //本例交换a和b的值,而p1和p2的值不变。这恰和例8.2相反
【例 8.4】
对输入的两个整数按大小顺序输出。
#include <stdio.h>
int main()
{ void swap(int *p1,int *p2);
int a,b;
int *pointer_1,*pointer_2; //pointer_1,pointer_2是int *型变量
printf("please enter two integer numbers:");
scanf("%d,%d",&a,&b);
pointer_1=&a;
pointer_2=&b;
if(a<b) swap(pointer_1,pointer_2);
//调用swap函数,用指针变量作实参
printf("max=%d,min=%d\n",*pointer_1,*pointer_2);
return 0;
}
void swap(int *p1,int *p2) //形参是指针变量
{ int *p;
p=p1; //下面3行交换p1和p2的指向
p1=p2;
p2=p;
}
错误
!!!!!
不能企图通过改变指针形参的值而使指针实参的值改变
!!!!
【例 8.5】
输入3个整数a,b,c,要求按由大到小的顺序将它们输出。用函数实现。
#include <stdio.h>
int main()
{ void exchange(int *q1, int *q2, int *q3); //函数声明
int a,b,c,*p1,*p2,*p3;
printf("please enter three numbers:");
scanf("%d,%d,%d",&a,&b,&c);
p1=&a;p2=&b;p3=&c;
exchange(p1,p2,p3);
printf("The order is:%d,%d,%d\n",a,b,c);
return 0;
}
void exchange(int *q1, int *q2, int *q3) //将3个变量的值交换的函数
{ void swap(int *pt1, int *pt2); //函数声明
if(*q1<*q2) swap(q1,q2); //如果a<b,交换a和b的值
if(*q1<*q3) swap(q1,q3); //如果a<c,交换a和c的值
if(*q2<*q3) swap(q2,q3); //如果b<c,交换b和c的值
}
void swap(int *pt1, int *pt2) //交换2个变量的值的函数
{ int temp;
temp=*pt1; //交换*pt1和*pt2变量的值
*pt1=*pt2;
*pt2=temp;
}
【例 8.6】
有一个整型数组a,有10个元素,要求输出数组中的全部元素。
#include <stdio.h>
int main()
{ int a[10];
int *p,i;
printf("please enter 10 integer numbers:");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
for(p=a;p<(a+10);p++)
printf("%d ",*p);
//用指针指向当前的数组元素
printf("\n");
return 0;
}
【例8.7】
通过指针变量输出整型数组a的10个元素
#include <stdio.h>
int main()
{ int i,a[10],*p=a; //p的初值是a,p指向a[0]
printf("please enter 10 integer numbers:");
for(i=0;i<10;i++)
scanf("%d",p++);
p=a; //重新使p指向a[0]
for(i=0;i<10;i++,p++)
printf("%d ",*p);
printf("\n");
return 0;
}
【例8.8】
将数组a中n个整数按相反顺序存放。
#include <stdio.h>
int main()
{ void inv(int *x,int n);
int i,a[10]={3,7,9,11,0,6,7,5,4,2};
printf("The original array:\n");
for(i=0;i<10;i++)
printf("%d ",a[i]);
printf("\n");
inv(a,10);
printf("The array has been inverted:\n");
for(i=0;i<10;i++)
printf("%d ",a[i]);
printf("\n");
return 0;
}
void inv(int *x,int n) //形参x是指针变量
{ int *p,temp,*i,*j,m=(n-1)/2;
i=x; j=x+n-1; p=x+m;
for(;i<=p;i++,j--)
{ temp=*i; *i=*j; *j=temp;} //*i与*j交换
return;
}
【例8.9】
改写例8.8,用指针变量作实参。
#include <stdio.h>
int main()
{ void inv(int *x,int n); //inv函数声明
int i,arr[10],*p=arr; //指针变量p指向arr[0]
printf("The original array:\n");
for(i=0;i<10;i++,p++)
scanf("%d",p); //输入arr数组的元素
printf("\n");
p=arr; //指针变量p重新指向arr[0]
inv(p,10); //调用inv函数,实参p是指针变量
printf("The array has been inverted:\n");
for(p=arr;p<arr+10;p++)
printf("%d ",*p);
printf("\n");
return 0;
}
void inv(int *x,int n) //定义inv函数,形参x是指针变量
{ int *p,m,temp,*i,*j;
m=(n-1)/2;
i=x;j=x+n-1;p=x+m;
for(;i<=p;i++,j--)
{ temp=*i;*i=*j;*j=temp;}
return;
}
【例 8.10】
用指针方法对10个整数按由大到小顺序排序。(选择排序法)
选择法
#include <stdio.h>
int main()
{ void sort(int x[],int n); //sort函数声明
int i,*p,a[10];
p=a; //指针变量p指向a[0]
printf("please enter 10 integer numbers:");
for(i=0;i<10;i++)
scanf("%d",p++); //输入10个整数
p=a; //指针变量p重新指向a[0]
sort(p,10); //调用sort函数
for(p=a,i=0;i<10;i++)
{ printf("%d ",*p); //输出排序后的10个数组元素
p++;
}
printf("\n");
return 0;
}
void sort(int x[],int n) //定义sort函数,x是形参数组名
{ int i,j,k,t;
for(i=0;i<n-1;i++)
{ k=i;
for(j=i+1;j<n;j++)
if(x[j]>x[k]) k=j;
if(k!=i)
{ t=x[i]; x[i]=x[k]; x[k]=t;}
}
}
起泡法
#include<stdio.h>
int main()
{
void pop(int *arr,int len);
int arr[10] = {4,3,5,7,9,2,1,6,8,10};
int *p = arr;
printf("排序前\n");
for(p=arr;p<arr+10;p++)
{
printf("%d\t",*p);
}
printf("\n");
p = arr;
pop(p,10);
printf("\n排序后\n");
for(p=arr;p<arr+10;p++)
{
printf("%d\t",*p);
}
return 0;
}
void pop (int *arr,int len)
{
int i,j,temp,*p=arr;
for(i=0;i<len;i++)
{
p=arr; //记得归位
for(j=i;j<len-1;j++,p++)
{
if(*(p)>*(p+1))
{
printf("%d---%d\n",*(p),*(p+1));
temp = *(p);
*(p) = *(p+1);
*(p+1) = temp;
}
}
}
}
【例 8.11】
输出二维数组的有关数据(地址和元素的值)。
#include <stdio.h>
int main()
{ int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
printf("%d,%d\n",a,*a); //0行起始地址和0行0列元素地址
printf("%d,%d\n",a[0],*(a+0)); //0行0列元素地址
printf("%d,%d\n",&a[0],&a[0][0]); //0行起始地址和0行0列元素地址
printf("%d,%d\n",a[1],a+1); //1行0列元素地址和1行起始地址
printf("%d,%d\n",&a[1][0],*(a+1)+0); //1行0列元素地址
printf("%d,%d\n",a[2],*(a+2)); //2行0列元素地址
printf("%d,%d\n",&a[2],a+2); //2行起始地址
printf("%d,%d\n",a[1][0],*(*(a+1)+0)); //1行0列元素的值
printf("%d,%d\n",*a[2],*(*(a+2)+0)); //2行0列元素的值
return 0;
}
【例 8.12】
有一个3×4的二维数组,要求用指向元素的指针变量输出二维数组各元素的值。
#include <stdio.h>
int main()
{ int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
int *p; //p是int *型指针变量
for(p=a[0];p<a[0]+12;p++) //使p依次指向下一个元素
{ if((p-a[0])%4==0) printf("\n"); //p移动4次后换行
printf("%4d",*p); //输出p指向的元素的值
}
printf("\n");
return 0;
}
【例 8.13】
输出二维数组任一行任一列元素的值。
#include <stdio.h>
int main()
{ int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23}; //定义二维数组a并初始化
int (*p)[4],i,j; //指针变量p指向包含4个整型元素的一维数组
p=a; //p指向二维数组的0行
printf("please enter row and colum:");
scanf("%d,%d",&i,&j); //输入要求输出的元素的行列号
printf("a[%d,%d]=%d\n",i,j,*(*(p+i)+j)); //输出a[i][j]的值
return 0;
}
比较:
① int a[4];(a有4个元素,每个元素都为整型)
② int (*p)[4];
第②种形式表示p所指的对象是有4个整型元素的一维数组。应该记住,此时p只能指向一个包含4个元素的一维数组,不能指向一维数组中的某一元素。p的值是该一维数组的起始地址。虽然**这个地址(指纯地址)**与该一维数组首元素的地址相同,但它们的基类型是不同的。
#include <stdio.h>
int main()
{ int a[4]={1,3,5,7}; //定义一维数组a,包含4个元素
int (*p)[4]; //定义指向包含4个元素的一维数组的指针变量
p=&a; //使p指向一维数组
printf("%d\n",(*p)[3]); //输出a[3],输出整数7
return 0;
}
【例8.30】
建立动态数组,输入5个学生的成绩,另外用一个函数检查其中有无低于60分的,输出不合格的成绩。
用指向数组的指针作函数参数
【例题 14】
有一个班,3个学生,各学4门课,计算总平均分数以及第n个学生的成绩。
#include <stdio.h>
int main()
{ void average(float *p,int n);
void search(float (*p)[4],int n);
float score[3][4]={{65,67,70,60},{80,87,90,81},{90,99,100,98}};
average(*score,12); //求12个分数的平均分
search(score,2); //求序号为2的学生的成绩
return 0;
}
void average(float *p,int n) //定义求平均成绩的函数
{ float *p_end;
float sum=0,aver;
p_end=p+n-1;
//n的值为12时,p_end的值是p+11,指向最后一个元素
for(;p<=p_end;p++)
sum=sum+(*p);
aver=sum/n;
printf("average=%5.2f\n",aver);
}
void search(float (*p)[4],int n)
//p是指向具有4个元素的一维数组的指针
{ int i;
printf("The score of No.%d are:\n",n);
for(i=0;i<4;i++)
printf("%5.2f ",*(*(p+n)+i));
printf("\n");
}
实参与形参如果是指针类型,应当注意它们的基类型必须一致。不应把int *型
的指针(即数组元素的地址)传给int (*)[4] 型
(指向一维数组)的指针变量,反之亦然。
【例 8.15】
在例8.14的基础上,查找有一门以上课程不及格的学生,输出他们的全部课程的成绩。
#include <stdio.h>
int main()
{ void search(float (*p)[4],int n); //函数声明
float score[3][4]={{65,57,70,60},{58,87,90,81},{90,99,100,98}};
//定义二维数组函数score
search(score,3); //调用search函数
return 0;
}
void search(float (*p)[4],int n)
//形参p是指向包含4个float型元素的一维数组的指针变量
{ int i,j,flag;
for(j=0;j<n;j++)
{ flag=0;
for(i=0;i<4;i++)
if(*(*(p+j)+i)<60) flag=1;
//*(*(p+j)+i)就是score[j][i]
if(flag==1)
{ printf("No.%d fails,his scores are:\n",j+1);
for(i=0;i<4;i++)
printf("%5.1f ",*(*(p+j)+i));
//输出*(*(p+j)+i)就是输出score[j][i]的值
printf("\n");
}
}
}
通过指针引用字符串
【例 8.16】
定义一个字符数组,在其中存放字符串″I love China!″,输出该字符串和第8个字符。
#include <stdio.h>
int main()
{ char string[]="I love China!"; //定义字符数组sting
printf("%s\n",string); //用%s格式声明输出string,可以输出整个字符串
printf("%c\n",string[7]); //用%c格式输出一个字符数组元素
return 0;
}
【例 8.17】
通过字符指针变量输出一个字符串。
#include <stdio.h>
int main()
{ char *string="I love China!"; //定义字符指针变量string并初始化
printf("%s\n",string); //输出字符串
return 0;
}
字符串的引用方式
char *string="I love China!";
==
char *string; 定义一个char *型变量
string=″I love China!″;
把字符串第1个元素的地址赋给字符指针变量string
只是把″I love China!″的第1个字符的地址赋给指针变量string。
可以对指针变量进行再赋值,如:
string=″I am a student.″; 对指针变量string重新赋值
可以通过字符指针变量输出它所指向的字符串,如:
printf(″%s\n″,string); %s可对字符串进行整体的输入输出
%s是输出字符串时所用的格式符,在输出项中给出字符指针变量名string,则系统会输出string所指向的字符串第1个字符,然后自动使string加1,使之指向下一个字符,再输出该字符……如此直到遇到字符串结束标志′\0′为止。注意,在内存中,字符串的最后被自动加了一个′\0′。
【例 8.18】
将字符串a复制为字符串b,然后输出字符串b。
#include <stdio.h>
int main()
{ char a[]="I am a student.",b[20]; //定义字符数组
int i;
for(i=0;*(a+i)!='\0';i++)
*(b+i)=*(a+i); //将a[i]的值赋给b[i]
*(b+i)='\0'; //在b数组的有效字符之后加'\0'
printf("string a is:%s\n",a);//输出a数组中全部有效字符
printf("string b is:");
for(i=0;b[i]!='\0';i++)
printf("%c",b[i]); //逐个输出b数组中全部有效字符
printf("\n");
return 0;
}
【例 8.19】
用指针变量来处理例8.18问题。
#include <stdio.h>
int main()
{ char a[]="I am a boy.",b[20],*p1,*p2;
p1=a;p2=b;
//p1,p2分别指向a数组和b数组中的第一个元素
for(;*p1!='\0';p1++,p2++) //p1,p2每次自加1
*p2=*p1;
//将p1所指向的元素的值赋给p2所指向的元素
*p2='\0'; //在复制完全部有效字符后加'\0'
printf("string a is:%s\n",a); //输出a数组中的字符
printf("string b is:%s\n",b); //输出b数组中的字符
return 0;
}
【例 8.20】
用函数调用实现字符串的复制。
1.用字符数组名作为函数参数
#include <stdio.h>
int main()
{ void copy_string(char from[], char to[]);
char a[]="I am a teacher.";
char b[]="You are a student.";
printf("string a=%s\nstring b=%s\n",a,b);
printf("copy string a to string b:\n");
copy_string(a,b); //用字符数组名作为函数实参
printf("\nstring a=%s\nstring b=%s\n",a,b);
return 0;
}
void copy_string(char from[], char to[]) //形参为字符数组
{ int i=0;
while(from[i]!='\0')
{ to[i]=from[i]; i++;}
to[i]='\0';
}
- 用字符型指针变量作实参
#include <stdio.h>
int main()
{ void copy_string(char from[], char to[]); //函数声明
char a[]="I am a teacher."; //定义字符数组a并初始化
char b[]="You are a student."; //定义字符数组b并初始化
char *from=a,*to=b; //from指向a数组首元素,to指向b数组首元素
printf("string a=%s\nstring b=%s\n",a,b);
printf("copy string a to string b:\n");
copy_string(from,to); //实参为字符指针变量
printf("\nstring a=%s\nstring b=%s\n",a,b);
return 0;
}
void copy_string(char from[], char to[]) //形参为字符数组
{ int i=0;
while(from[i]!='\0')
{ to[i]=from[i]; i++;}
to[i]='\0';
}
指针变量from的值是a数组首元素的地址
指针变量to的值是b数组首元素的地址。
它们作为实参,把a数组首元素的地址和b数组首元素的地址
传递给形参数组名from和to(它们实质上也是指针变量)。
- 用字符指针变量作形参和实参
#include <stdio.h>
int main()
{ void copy_string(char *from, char *to);
char *a="I am a teacher."; //a是char*型指针变量
char b[]="You are a student."; //b是字符数组
char *p=b; //使指针变量p指向b数组首元素
printf("string a=%s\nstring b=%s\n",a,b); //输出a串和b串
printf("copy string a to string b:\n");
copy_string(a,p); //调用copy_string函数,实参为指针变量
printf("\nstring a=%s\nstring b=%s\n",a,b); //输出改变后的a串和b串
return 0;
}
void copy_string(char *from, char *to) //定义函数,形参为字符指针变量
{ for(;*from!='\0';from++,to++)
{ *to=*from;}
*to='\0';
}
or
void copy_string(char from[],char to[])
{ char *p1, *p2;
p1=from;p2=to;
while((*p2++=*p1++)!='\0');
}
字符指针作函数参数
使用字符指针变量和字符数组的比较
-
字符数组由若干个元素组成,每个元素中放一个字符,而字符指针变量中存放的是地址(字符串第1个字符的地址),绝不是将字符串放到字符指针变量中。
-
赋值方式:可以对字符指针变量赋值,但不能对数组名赋值。(数组名是常量)
课后习题
本章习题均要求使用指针方法处理。
习题 1
输入3个整数,要求按由小到大的顺序输出。
#include<stdio.h>
int main()
{
void swap(int*,int*);
int a,b,c ;
int *p=&a,*q=&b,*t=&c;
printf("请输入三个数");
scanf("%d,%d,%d",&a,&b,&c);
if(*p<*q)
{
swap(p,q);
}
if(*p<*t)
{
swap(p,t);
}
if(*q<*t)
{
swap(q,t);
}
printf("%d,%d,%d",*p,*q,*t);
return 0;
}
void swap(int*a,int*b)
{
int temp = *a;
*a = *b;
*b = temp;
}
习题2
输入3个字符串,要求按由小到大的顺序输出
字符串的比较可以使用strcmp函数,返回值>0表示大于,返回值小于0表示小于,返回追等于0表示相同。其他的比较排序思路与数字的排序交换没有区别,逐个进行比较先找出最大的,然后找出第二大的。
#include<stdio.h>
#include<string.h>
int main()
{
char str[3][50];
char *p[3],*temp;
int i,j;
printf("please enter ");
for(i=0;i<3;i++)
{
p[i] = str[i];
gets(p[i]);
}
for(i=0;i<2;i++)
{
for(j=i+1;j<3;j++)
{
if(strcmp(p[i],p[j])>0)
{
temp = p[i];
p[i] = p[j];
p[j] = temp;
}
}
}
printf("%s %s %s\n", p[0], p[1], p[2]);
}
习题 3
输入10个整数,将其中最小的数与第一个数对换, 把最大的数与最后一个数对换
①输人10个数;
②进行处理;
③输出10个数。
解题思路: 在进行数值逐个比较的同时找到最小值的空间地址以及最大值的空间地址,使用这两个空间中的数据最终与第一和最后数据进行对换即可。
要注意覆盖问题!!!
方法1 普通指针
输出函数
void input(int *array,int len)
{
int *m;
for(m=array,printf("enter 10 num\n");m<array+len;scanf("%d",m++));
}
交换函数(没有问题)
void handble(int *array,int len)
{
// 最小值
int *i,*j,*min,*man,t;
for(i=array,min = i;i<array+len,i++)
for(j=i+1;j<array+len;*min>*j?min=j++:j++)
t = *min;
*min=*array;
*array = t;
// 最大值
for(i=array+1,max = i;i<array+len;i++)
for(j+i+1;j<array+len;*max<*j?max=j++:j++)
t = *max;
*max = *(array+len-1);
*(array+len-1) = t;
}
输出函数
void print(int *array, int len)
{
int *i;
for(i=array,printf("SORT BY :");i<array+len;printf("%d",*i++));
}
交换函数(有问题)
void handble(int *array,int len)
{
int max = array[0],min = array[9];
int *maxp = NULL,*minp = NULL;
int i;
for(i=1;i<len;i++)
{
if(min>array[i])
{
min = array[i];
minp = &array[i];
}
if(max<array[i])
{
max = array[i];
maxp = &array[i];
}
}
// 小心min 或者 max被换掉
// 交换最小的
int tmp;
tmp = *minp;
*minp = array[0];
array[0] = tmp;
// 为了防止array[0]是最大的数字
// 此时*minp 储存着 array[0]的数字
if(*maxp = *minp)
{
}
else
{
tmp = *maxp;
*maxp = array[9];
array[9] = tmp;
}
}
方法2:(利用动态内存分配)
int *array;
array = (int*)malloc(10*sizeof(int));
作业
#include<stdio.h>
int main()
{
void handble(int *array,int len);
int array[10]= {9,7,5,3,10,8,6,4,1,2};
int *i;
printf("对换前:\n");
for(i=array;i<array+10;i++)
printf("%d\t",*i);
handble(array,10);
printf("\n对换后:\n");
for(i=array;i<array+10;i++)
printf("%d\t",*i);
return 0;
}
void handble(int *array,int len)
{
int *i,*j,*min,*max,t;
for(i=array,min=i;i<array+len;i++)
{
for(j=i+1;j<array+len;(*min>*j)?min=j++:j++);
}
t = *min;
*min = *array;
*array=t;
for(i=array+1,max=i;i<array+len;i++)
{
for(j=i+1;j<array+len-1;(*max<*j)?max=j++:j++);
}
t = *max;
*max = *(array+len-1);
*(array+len-1) = t;
}
习题 4 作业
.有n个整数,使前面各数顺序向后移m个位置,最后m个数变成最前面m个数,见图8.43。 写一函数实现以上功能,在主函数中输人n个整数和输出调整后的n个数。
双指针搬运
for(p=a,q=b;p<=(a+n-m);p++,q++);
指针
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
void move(int *array,int n,int m);
int number[50],n,m,i,j;
printf("Please enter the number of numbers: ");
scanf("%d", &n);//先确定要输入多少个数字
printf("Please enter %d numbers: ", n);
for (i = 0; i < n; i++) {
scanf("%d", &number[i]);//输入指定个数的数字
}
printf("Number of positions to move: ");
scanf("%d", &m);//确定要向后移动多少个位置
move(number,n,m);
for (i = 0; i < n; i++) {
printf("%d ", number[i]);
}
printf("\n");
return 0;
}
void move(int *array,int n,int m)
{
int end = n-m;
int i,j;
for(i=0;i<m;i++)
{
int *p = array+end+i;
int tmp = *p;
for(j=end+i;j>i;j--)
{
*p = *(p-1);
p--;
}
*(array+i) = tmp;
}
}
递归
#include<stdio.h>
int* move(int str[],int n,int m)
{
int *p,str_end;
if(m>0)
{
str_end=*(str+n-1);
for(p=str+n-1;p>str;p--)
*p=*(p-1); // 每个都后移一位
*p=str_end;
m--;
}
if(m>0)
move(str,n,m); //递归,循环后移
else
return p;
}
int main()
{
int a[20],i,m,n;
scanf("%d %d",&n,&m);
for(i=0;i<n;i++)
scanf("%d",&a[i]);
move(a,n,m);
for(i=0;i<n;i++)
printf("%d ",a[i]);
return 0;
}
链表
队列
习题 5
有n个人围成一圈,顺序排号。从第1个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位。
解题思路: 从第一个人开始,逐个报数,谁报3就退出,并且重置报数,直到最后一个人后,又重新从第一个人继续报数,直到最终只剩一个人的时候退出即可。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
int pep[128],n,i;
printf("Please input how many people: ");
scanf("%d",&n);
for(i=0;i<n;i++)
pep[i] = i+1; // 赋值
int remain = n;
int off =0;
int *p = NULL;
while(remain>1) //直到还剩一个人为止
{
p = pep;
while(p!=pep+n) // 当没有转完一圈
{
if((*p)!=0) //若这个位置人还在
{
off++; //报数
if(off==3) //否则当前的人即将要报的数字是3
{
*p=0; //则剔除这个人
off=0; //并且重新开始计数,下边会++,所以是从1开始报数
remain--;
}
}
p++;
}
}
for(i=0;i<n;i++)
{
if(pep[i]!=0)
printf("Serial number of the remaining person:%d\n", pep[i]);
}
}
链表
队列
习题 6
写一函数,求一个字符串的长度。在main函数中输入字符串,并输出其长度。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
int mystrlen( char *str);
char buff[100];
printf("Please enter a string: ");
gets(buff);
printf("string len:%d\n", mystrlen(buff));
return 0;
}
int mystrlen( char *str){
int len =0;
char *ptr = str;
while(*ptr!='\0')
{
ptr++;
len++;
}
return len;
}
作业
#include <stdio.h>
int main()
{
int my_strlen(char *str);
char str[1000];
printf("Please enter a string: ");
gets(str);
printf("string len:%d\n", my_strlen(str));
return 0;
}
int my_strlen(char *str)
{
int len = 0;
char *ptr = str;
while (*ptr != '\0') {
ptr++;
len++;
}
return len;
}
习题 7
有一字符串,包含n个字符。写一函数,将此字符串中从第m个字符开始的全部字符复制成为另一个字符串。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
char* mycmp(char *str ,int m);
char str1[1024], *len=NULL;
int m;
printf("Please enter a string: ");
gets(str1);
printf("Please enter a location to start copying: ");
scanf("%d",&m);
if(m<0||m>strlen(str1))
{
printf("Illegal location entered\n");
return -1;
}
else
{
// mycmp(str1,m);
len = mycmp(str1,m);
puts(len);
return 0;
}
}
char* mycmp(char *str ,int m){
char str2[100];
char *ptr = str+m;
char *ptr2 = str2;
while(*ptr !='\0')
{
*ptr2++ = *ptr++;
}
*ptr2 = '\0'; //不要忘了字符串结尾标志
// puts(str2);
return str2;
}
习题 8
输入一行文字,找出其中大写字母、小写字母、空格、数字以及其他字符各有多少。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
char str[100];
printf("please enter a string");
gets(str);
int upper = 0,lower = 0,digit =0,space = 0,other = 0;
char *ptr = str;
while(*ptr!='\0')
{
if(*ptr>='a'&&*ptr<='z'){
upper++;
}
else if (*ptr>='A'&& *ptr<='Z'){
lower++;
}
else if(*ptr>='0'&&*ptr<='9')
{
digit++;
}
else if(*ptr==' '){
space++;
}
else{
other++;
}
ptr++;
}
printf("upper:%d; lower:%d; digit:%d; space:%d; other:%d\n", \
upper, lower, digit, space, other);
}
习题 9
写一函数,将一个3x3的整型矩阵转置。
解题思路: 矩阵转置就是行变列,列变行,说白了就是 arry[i][j] 转换为 arry[j][i] ; 但是需要注意的是,
一. 因为行列个数可能并非相同,转换后行数或者列数变多了或者变少,因此不能直接转换。需要重新申请空间存储转换后的数据。
二. 二维数组是线性扁平化存储的,无法确定列数的情况下传参后,在函数中使用时需要头指针向后偏移 列数*第n行 才能访问到第n行的数据。例如在函数中访问 arry[i][j] ,需要通过arry + col_num*i + j
方式进行访问。
指针法
#include <stdio.h>
int main()
{
void trans(int (*p)[3],int x ,int y);
int a[3][3] = {1,2,3,4,5,6,7,8,9};
int i,j;
trans(a,3,3);
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
{
printf("%d\t",*(*(a+i)+j));
}
printf("\n");
}
}
void trans (int (*s)[3],int x,int y)
{
int i,j,t;
for(i=0;i<x;i++)
{
for(j=0;j<i;j++)
{
t = *(*(s+i)+j);
*(*(s+i)+j) = *(*(s+j)+i);
*(*(s+j)+i) = t;
}
}
}
动态内存法
习题 10
将一个5x5的矩阵中最大的元素放在中心,4个角分别放4个最小的元素(顺序为从左到右,从上到下依次从小到大存放),写一函数实现之。用main函数调用。
作业 将运用数组改为运用指针解决问题,同时起气泡和选择法
起泡法
二维数组转成一维数组;
对一维数组进行指针法排序
一维数组转成二维数组
#include <stdio.h>
int main()
{
void max(int *x,int *y);
void min(int *a,int x,int y);
void pop(int *a,int x,int y);
void print(int *a,int x,int y);
int a[5][5] = {{1,2,4,3,5},{6,7,9,8,11},{10,12,13,14,15},{16,17,18,19,20},{21,22,23,24,25}};
int x=5,y=5;
printf("")
print(*a,5,5);
pop(*a,5,5);
print(*a,5,5);
max(*a+x*y-1,*a+x*y/2);
min(*a,x,y);
print(*a,5,5);
return 0;
}
void pop(int *a,int x,int y)
{
int i,j,temp;
for(i=0;i<x*y-1;i++)
{
for(j=0;j<x*y-i-1;j++)
{
if(*(a+j)>*(a+j+1))
{
temp = *(a+j);
*(a+j) = *(a+j+1);
*(a+j+1) = temp;
}
}
}
}
void print(int *a,int x,int y)
{
int i;
for(i=0;i<x*y;i++)
{
printf("%d\t",*(a+i));
if((i+1)%5==0 )
printf("\n");
}
printf("\n");
}
void max(int *a,int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void min(int *a,int x,int y)
{
// 倒数第二小
int temp = *(a+1);
*(a+1) = *(a+y-1);
*(a+y-1) = temp;
// 倒数第三小
temp = *(a+2);
*(a+2) = *(a+(x-1)*y);
*(a+(x-1)*y) = temp;
// 倒数第四小
temp = *(a+3);
*(a+3) = *(a+(x-1)*y+y-1);
*(a+(x-1)*y+y-1) = temp;
}
1 2 4 3 5
6 7 9 8 11
10 12 13 14 15
16 17 18 19 20
21 22 23 24 25
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
1 5 21 13 2
6 7 8 9 10
11 12 25 14 15
16 17 18 19 20
3 22 23 24 4
选择法
void select(int *a,int x,int y)
{
int i,j,k,temp;
for(i=0;i<x*y-1;i++)
{
k=i;
for(j=i+1;j<x*y-1;j++)
{
if(*(a+j)<*(a+i))
{
k=j;
}
}
temp = *(a+k);
*(a+k) = *(a+i);
*(a+i) = temp;
}
}
习题 11
在主函数中输入10个等长的字符串。用另一函数对它们排序。然后在主函数输出这10个已排好序的字符串。
解题思路: 排序方式与数字比较没什么不同,先遍历比较找出最大的字符串,与第一个字符串进行交换,然后剩下的进行比较找出最大的字符串与第二个交换…
需要主机的就是字符串的比较采用strcmp接口,返回值大于0表示第一个字符串大于第二个字符串
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
void sort(char s[10][50]);
char str [10][50];
printf("Please enter ten strings:\n");
int i;
for(i=0;i<10;i++)
{
gets(str[i]);
}
sort(str);
printf("\n");
for(i=0;i<10;i++)
{
puts(str[i]);
}
return 0;
}
void sort(char s[10][50])
{
int i,j;
for(i=0;i<9;i++)
{
for(j=i+1;j<10;j++)
{
if(strcmp(s[i],s[j])>0)
{
char tmp[50];
strcpy(tmp,s[i]);
strcpy(s[i],s[j]);
strcpy(s[j],tmp);
}
}
}
}
习题 12
用指针数组处理上一题目,字符串不等长
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
void sort(char *s[10]);
char *str[10];
printf("Please enter ten strings:\n");
int i;
for(i=0;i<10;i++)
{
str[i] = (char*)malloc(sizeof(char));//为每一个指针分配空间
gets(str[i]);
}
sort(str);
printf("\n");
for(i=0;i<10;i++)
{
puts(str[i]);
}
return 0;
}
void sort(char *s[10])
{
int i,j;
for(i=0;i<9;i++)
{
for(j=i+1;j<10;j++)
{
if(strcmp(s[i],s[j])>0)
{
char *tmp = s[i]; //指针的好处在于直接通过赋值可以改变指向
s[i] = s[j];
s[j] = tmp;
}
}
}
}
习题 13
习题 14—作业
将n个数按输入时顺序的逆序排列,用函数实现。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
void rerand(int *array,int n);
int array[10];
printf("Please enter ten numbers:");
for (int i = 0; i < 10; i++) {
scanf("%d", &array[i]);
}
rerand(array,10);
for (int i = 0; i < 10; i++) {
printf("%d ", array[i]);
}
return 0;
}
void rerand(int *array, int n)
{
int *start = array;
int *end = array+n-1;
for(;start<end;start++,end--)
{
int tmp = *start;
*start = *end;
*end = tmp;
}
}
作业
#include<stdio.h>
//#include<string.h>
//#include<stdlib.h>
int main()
{
void rerand(int *array,int n);
int array[10] = {1,3,5,2,4,6,8,10,7,9},i;
rerand(array,10);
for ( i = 0; i < 10; i++) {
printf("%d ", array[i]);
}
return 0;
}
void rerand(int *array, int n)
{
int temp;
int *start = array;
int *end = array+n-1;
for(;start<end;start++,end--)
{
temp = *start;
*start = *end;
*end = temp;
}
}
习题 15
有一个班4个学生,5门课程。
①求第1门课程的平均分;
②找出有两门以上课程不及格的学生,输出他们的学号和全部课程成绩及平均成绩;
③找出平均成绩在90分以上或全部课程成绩在85分以上的学生。
分别编3个函数实现以上3个要求。
4个学生,5门课程就是一个4x5的二维数组,
求第一门课的平均分,就是将第0列数据相加除以学生人数
遍历每个学生的成绩,判断不及格次数,若大于2则输出信息即可
统计每个学生总成绩,以及对每门课程成绩进行判断即可
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
void avg(int array[][5],int n);
void fail(int array[][5],int n);
int exce(int array[][5],int n);
int i,j;
int array[4][5];
printf("Please enter a 4x5 matrix:\n");
for (i = 0; i < 4; i++) {
for (j = 0; j < 5; j++) {
scanf("%d", &array[i][j]);
}
}
avg(array,4);
fail(array,4);
exce(array,4);
return 0;
}
void avg(int array[][5],int n)
{
double sum = 0;
int i;
for(i=0;i<n;i++)
{
sum+=array[i][0];
}
printf("sum = %lf",sum/n);
}
void fail(int array[][5],int n)
{
printf("Information on students who fail in more than two courses: ");
int i,j;
for(i=0;i<n;i++)
{
int failnum = 0,sum;
for(j=0;j<5;j++)
{
if(array[i][j]<60)
{
failnum++;
}
}
if(failnum<2)
{
continue;
}
else
{
printf("seq:%d ", i + 1);
printf("score: ");
for (j = 0; j < 5; j++) {
sum += array[i][j];
printf("%d ", array[i][j]);
}
printf("avg:%lf ",sum/5);
printf("\n");
}
}
}
void exce(int array[][5],int n)
{
int i,j;
for(i=0;i<n;i++)
{
int sum = 0,count =0;
for(j=0;j<5;j++)
{
sum+=array[i][j];
if(array[i][j]>85)
count++;
}
if((sum/n)>90||count==5)
printf("Excellent students: %d\n", i + 1);
}
}
习题 16
输入一个字符串,内有数字和非数字字符,例如:A123x456 17960? ,302tab5876,将其中连续的数字作为一个整数,依次存放到一数组a中。例如,123放在a[0],456放在a1[1]…统计共有多少个整数,并输出这些数。
遇到数字字符,则开始统计连续数字字符的个数,统计完毕后,则从右往左每次乘以10(除了个位数)作为数字的单位,最终相加得到数字;然后越过这个数字,从后边继续查找。
#include<stdio.h>
#include<string.h>
int main()
{
void strfun(char*str);
char str[] = "A12345Bcd4567ef891";
strfun(str);
return 0;
}
void strfun(char *str)
{
int trans(char *str,int i);
char *ptr =str;
char str1[100] = {'\0'};
int num[50],i=0,j=0;
while(*ptr !='\0')
{
// 如果指向的是数字
if(*ptr>='0'&& *ptr<='9')
// 如果是数字的末尾
if(*(ptr+1)<'0'||*(ptr+1)>'9')
{
// printf("\nptr = %c\n",*ptr);
str1[i] = *ptr;
// puts(str1);
// str1 的长度为i+1
num[j++] = trans(str1,i+1) ;
printf("\n num =%d\n",num[j-1]);
i=0; // 重置i
ptr++;
}
else
{
// printf("\nptr = %c\n",*ptr);
str1[i++] = *ptr++;
}
else
{
// printf("\nptr = %c\n",*ptr);
ptr++;// 下一个
}
}
// 输出,其中j为整数个数
printf("一共有%d个数字\n",j);
for(;j>0;j--)
printf("%d\t",num[j-1]);
}
//字符型变整数
int trans(char *str,int i)
{
int num=0;
char *p = str;
while(i--)
{
num = num*10 + ((*p++)-'0');
}
return num;
}
习题 17
写一函数,实现两个字符串的比较。即自己写一个strcmp函数,函数原型为int strcmp(char * p1 ,char * p2); 设p1指向字符串s1, p2指向字符串s2。要求当s1=s2时,返回值为0;若s1≠s2,返回它们二者第1个不同字符的ASCII码差值(如"BOY"与"BAD" ,第2个字母不同,0与A之差为79- 65=14)。如果s1>s2,则输出正值;如果s1<s2,则输出负值。
#include<stdio.h>
int main()
{
int my_strcmp(char *str1,char *str2);
char str1[100],str2[100];
gets(str1);
gets(str2);
puts(str1);
puts(str2);
printf("ans = %d",my_strcmp(str1,str2));
return 0;
}
int my_strcmp(char *str1,char *str2)
{
char *p1 = str1,*p2 = str2;
int num=0;
while(*p1!='\0'&&*p2!='\0')
{
if(*p1!=*p2)
{
num = (*p1-*p2);
break;
}
p1++;
p2++;
}
// 同时指向末尾
if(*p1 == '\0' || *p2=='\0')
{
num = *p1-*p2;
}
return num;
}
作业
#include<stdio.h>
int main()
{
int my_strcmp(char *str1,char *str2);
char str1[100],str2[100];
gets(str1);
gets(str2);
printf("差值是= %d",my_strcmp(str1,str2));
return 0;
}
int my_strcmp(char *str1,char *str2)
{
char *p1 = str1,*p2 = str2;
int num=0;
while(*p1!='\0'&&*p2!='\0')
{
if(*p1!=*p2)
{
num = (*p1-*p2);
break;
}
p1++;
p2++;
}
// 同时指向末尾
if(*p1 == '\0' || *p2=='\0')
{
num = *p1-*p2;
}
return num;
}
习题 18
编一程序,输入月份号,输出该月的英文月名。例如,输人3,则输出"March" ,要求用指针数组处理。
字符串指针
month 是一个含有12个指针的。指针指向字符串,的字符串指针数组
month[2]是一个指针,这个指针指向February
int main()
{
int month;
char *Month[12] = { "January","February","March","April","May","June",
"July","August","September","October","November","December" };
while (1) {
printf("Please enter the month: ");
scanf("%d", &month);
if (month < 1 && month>12) {
printf("Input error, Month should be greater than 0 and less than 12\n");
}
printf("%s\n", Month[month - 1]);
}
return 0;
}
方法二
#include <stdio.h>
int main()
{
int n;
char *Month[12] = {"January","February","March","April","May","June","July","August","September","October","November","December"};
printf("请输入月份:\n");
scanf("%d",&n);
printf("英文是:%s\n",*(Month + n - 1));
// printf("英文是:%s\n",(Month + n - 1));
}
习题 19
(1) 编写一个函数new,对n个字符开辟连续的存储空间,此函数应返回一个指针(地址),指向字符串开始的空间。new(n)表示分配n个字节的内存空间。
(2)写一函数free,将前面用new函数占用的空间释放。free§表示将p(地址)指向的单元以后的内存段释放。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
void *NEW(int n);
void FREE(char *p);
int num;
char *str = NULL;
printf("Please enter number: ");
scanf("%d", &num);
printf("before new p--%p:%s\n", str, str);//申请空间之前,查看指针的地址和指向空间数据
str = (char*)NEW(num);
printf("after new p--%p:%s\n",str,str);
printf("Please enter a string:\n");
scanf("%s", str);
printf("before free p--%p:%s\n", str, str);//释放空间之前,查看指针的地址和指向空间数据
FREE(str);
printf("after free p--%p:%s\n", str, str);//释放空间之后,查看指针的地址和指向空间数据
return 0;
}
void *NEW(int n)
{
return malloc(n);
}
void FREE(char *p)
{
return free(p);
}
习题 20
用指向指针的指针的方法对5个字符串排序并输出。
指向指针的指针其实就是二级指针,使用二级指针的保存一级指针的地址,让这个一级指针指向具体的数据空间; 定义一个字符串指针数组包含5个元素,每个元素可以保存一个字符串的首地址,而这个地址指向的是具体的字符串数据空间,通过指针访问实现对指向空间内的字符串进行比较排序交换即可。
习题 21
用指向指针的指针的方法对n个整数排序并输出。要求将排序单独写成一个函数。n个整数在主函数中输入,最后在主函数中输出
指向指针的指针其实就是二级指针,使用二级指针的保存一级指针的地址,让这个一级指针指向具体的数据空间。排序就是按照每个元素指针指向空间中的数据进行比对排序即可。