指针
1.引言
int a;
a = 100;
int b = a;
在C语言里面,同一个变量a,有两层含义
1) 左值:代表该变量的存储单元地址
2) 右值:代表该变量的值
————————————————————————————————————————————————————————————————————————————————————————————————
2.指针概念
地址:分配给每个变量的内存单元都有一个值(编号)
指针: 指针是一个量,对应了一块内存区域,是某个内存单元的地址。
一个变量的地址称为该变量的指针
————————————————————————————————————————————————————————————————————————————————————————————————
3.定义指针变量
存地址的变量叫做指针变量
指针变量的定义:
类型名 * 变量名
类型必须和他所指向的那个变量的类型相同
int a = 10;
int* p = &a;//int *p; p = &a;
int c = a;//int c ;c = a;
* 间接访问运算符
(*地址) 地址对应的变量
*p <-> a
*&a <-> a
不能将一个数值赋值给指针变量,而只能给一个变量的地址!!!
int *q;
*q=50;//此种做法是危险的,因为此时你不知道q保存的是谁的地址,
也就不知道修改了哪里的值;
int *q=NULL;//q没有指向任何地方;
*q=50;//错误,没有指向任何地方,也就没有可以修改的值。
上面两种情况可能造成段错误,还有数组越界,尝试修改只读数据也会早成段错误;
注意发生段错误,可以用打印法进行查错。
正确做法:
int a=50;
int *q=&a;
————————————————————————————————————————————————————————————————————————————————————————————————
4.数组与指针
指针与数组元素
int a[10] = {1,2,3,4,5};
int *p = &a[2];
数组名代表这个数组的首地址
int *q = a//int *q = &a[0];
//int *q; q = a;
把100 赋值给a[0],有几种方式
a[0] = 100;
*q = 100;
*&a[0] = 100;
把200赋值给a[i]有几种方式
a[i] = 200;
q[i] = 200; //下标法
*(a + i) = *( q + i) = 200;//指针法
指针的加减并不是单纯意义上的数学加减,而是加减指向单元的长度(指针的类型)
数组名是指向这个数组第一个元素的常量指针
用数组名和指针做参数
1) 形参和实参都用数组名
2) 形参用数组名,实参用指针
3) 实参用数组名,形参用指针
4) 形参和实参都用指针
这四种是等价的,都可以用;
13、写一个函数实现将任意字符串按照ASC值从小到大顺序排列。
函数原型为:
char *sort(char *s);
写一个函数将任意给定的两个字符串取交集
14、函数原型为:
char *jiaoji(char *s,char *s1,char *s2);
若s1: abcddebcdf ==》去重后的s1 abcdef
s2: bcdfgb
15、写一个函数将任意给定的两个字符串取并集
函数原型为:
char *bingji(char *s,char *s1,char *s2);
若s1: abcdde
s2: bcdfg
则返回的是 abcdefg
求交集
#include<stdio.h>
#include<string.h>
char *sort(char *s)
{
int i,j,n;
char temp;
n=strlen(s);
for(i=0;i<n-1;i++)
{
for(j=0;j<n-1;j++)
{
if(*(s+j)>*(s+j+1))
{
temp=*(s+j);
*(s+j)=*(s+j+1);
*(s+j+1)=temp;
}
}
}
return(s);
}
char *jiaoji(char *s,char *s1,char *s2)
{
char d[100]={0},e[100]={0};
char *s3=d,*s4=e;
int i,j=0,n1,n2,n3,n4,k=0;
n1=strlen(s1),n2=strlen(s2);
for(i=0;i<n1;i++)
{
if(i==0)
{
s3[j]=s1[i];
}
if(s3[j]!=s1[i])
{
s3[++j]=s1[i];
}
}
puts(s3);
n3=strlen(s3);
j=0;
for(i=0;i<n2;i++)
{
if(i==0)
{
s4[j]=s2[i];
}
if(s4[j]!=s2[i])
{
s4[++j]=s2[i];
}
}
puts(s4);
n4=strlen(s4);
for(i=0;i<n3;i++)
{
for(j=0;j<n4;j++)
{
if(s3[i]==s4[j])
{
break;
}
}
if(j!=n4)
{
s[k++]=s3[i];
}
}
return s;
}
int main (void)
{
char a[100]={0},b[100]={0},c[100]={0};
scanf("%s%s",a,b);
char *s1=sort(a),*s2=sort(b),*s=c;
puts(jiaoji(s,s1,s2));
return 0;
}
求并集
#include<stdio.h>
#include<string.h>
char *sort(char *s)
{
int i,j,n;
char temp;
n=strlen(s);
for(i=0;i<n-1;i++)
{
for(j=0;j<n-1;j++)
{
if(*(s+j)>*(s+j+1))
{
temp=*(s+j);
*(s+j)=*(s+j+1);
*(s+j+1)=temp;
}
}
}
return(s);
}
char *jiaoji(char *s,char *s1,char *s2)
{
char d[100]={0},e[100]={0};
char *s3=d,*s4=e;
int i,j=0,n1,n2,n3,n4,k=0;
n1=strlen(s1),n2=strlen(s2);
for(i=0;i<n1;i++)
{
if(i==0)
{
s3[j]=s1[i];
}
if(s3[j]!=s1[i])
{
s3[++j]=s1[i];
}
}
puts(s3);
n3=strlen(s3);
j=0;
for(i=0;i<n2;i++)
{
if(i==0)
{
s4[j]=s2[i];
}
if(s4[j]!=s2[i])
{
s4[++j]=s2[i];
}
}
puts(s4);
n4=strlen(s4);
for(i=0;i<n3;i++)
{
for(j=0;j<n4;j++)
{
if(s3[i]==s4[j])
{
break;
}
}
if(j==n4)
{
*(s4+n4+k)=s3[i];
k++;
}
}
s=s4;
return s;
}
int main (void)
{
char a[100]={0},b[100]={0},c[100]={0},g[100]={0};
scanf("%s%s",a,b);
char *s1=sort(a),*s2=sort(b),*s=c,*s5=g;
s5=sort(jiaoji(s,s1,s2));
puts(s5);
return 0;
}
在32位机里面,无论什么什么指针类型(char *,double *,int *, short *)都是4个字节,32bit;
打印验证:printf(“%d\n”,sizeof(char *));
结果都是4;
————————————————————————————————————————————————————————————————————————————————————————————————
5.多维数组与指针
int a[10];
a a[0]
a &a[0]
int * const(表示&a[0]的类型)
int b[3][4];//int[4] b[3];
b b[0]
b &b[0]
int [4] * const //const int (*)[4](表示&b[0]的类型)
b[0] b[0][0]
b[0] &b[0][0]
int *const
int a[5];
int b[2][3];
(gdb) p &a
表示&a的类型 = (int (*)[5]) a的地址是0xbffff04c
(gdb) p &a[0]
(表示&a[0]的类型) = (int *) a[0]的地址是0xbffff04c
(gdb) p &b
(表示&b的类型)= (int (*)[2][3]) 0xbffff060
(gdb) p &b[0]
(表示&b[0]的类型)= (int (*)[3]) 0 xbffff060
(gdb) p &b[0][0]
(表示&b[0][0]的类型)= (int *) 0xbffff060
此题&a的类型是int *[4] 即int [4]*
那么&a+1就是加一个指针类型 int [4]*;
&a[0]+1就是就是&a[1];
—————————————————————————————————————————————————————————
6.字符串与指针
char string[] = "hello world";
char *q = string;
char *string = "hello world";//只读数据
string += 2;//string = string + 2;
————————————————————————————————————————————————————————————————————————————————————————————————
7.数组指针与指针数组
数组指针是一个指针,只是因为这个指针指向了一个数组,所以叫数组指针
类型 (*指针名)[常量表达式] 行指针
看优先级,(指针有(),所以为数组指针)(用百分之10)
详见例题8.c
指针数组是一个数组,只是因为这个数组里面都是指针,所以叫指针数组
类型 * 数组名[常量表达式]
看优先级(数组有(),所以为指针数组) (用百分之90)
注意:
Int a[3][4}={1,2,3,.......,8}
Int (*p)[4]=&a[0]
P=&a[0];
Int x[]=等价于int *x;
Void fun(int a[][4],int n)等价于void fun (int (*a)[4],int n])
————————————————————————————————————————————————————————————————————————————————————————————————
8.函数指针与指针函数
函数指针是一个指针,只是因为这个指针指向的是一个函数,所以叫函数指针
返回值类型 (*函数名)(函数参数列表)
指针优先级高,所以为函数指针;(用百分之10)
指针函数是一个函数,只是因为返回的是一个指针,所以叫指针函数
类型 * 函数名(函数参数列表)
函数优先级高,所以为指针函数(用百分之90)
函数名代表这个函数的地址!!!
#include<stdio.h>
int sum(int a,int b)
{
return a + b;
}
int sub(int a,int b)
{
return a - b;
}
int* func(int a,int *x)
{
}
void function(int *x,int *y)
{
}
int main(int argc,char *argv[])
{
int result;
int a = 3,b = 4;
//result = sum(a,b);
int (*p)(int a,int b);//int (*p)(int ,int);
/*
p = sum;//int (*p)(int ,int ) = sum;
result = p(3,4);
*/
p = ∑
result = (*p)(a,b);
printf("result = %d\n",result);
p = sub;
int * (*q)(int ,int *) = func;
void (*m)(int *,int *) = function;
m(&a,&b);//function(&a,&b);
return 0;
}
————————————————————————————————————————————————————————————————————————————————————————————————
9.二级指针
保存一级指针地址的变量叫做二级指针变量
称为指向指针的指针
类型 ** 指针名
*(*(a+i)+j)=a[i][j]
————————————————————————————————————————————————————————————————————————————————————————————————
10.main函数参数
argc代表参数个数,argv代表每个参数
————————————————————————————————————————————————————————————————————————————————————————————————
11.const与指针(两部分结合起来理解 很重要的知识点)
详见图示
int const a;
const int a=10;//这两个等价,都是定义一个整形常量a,值不能更改;
int * const b;//一个指向整型数的常指针b,也就是说指向的值可以更改,但是地址(对应指针指向的地方)不能更改;
Const int * b;//一个指向常整型数地址的指针,指向的地址可以更改(对应的指针可以指向其他地方),但是地址上的值不能更改(对应的指针不能改变指向的值);
Const int * const c;一个指向常整形数的常指针,指向的地址和值都不能更改;
诀窍:只要看const在*的哪边,如果是左边,就是指向的值不能更改,如果是右边,就是指向的地址不能更改。
————————————————————————————————————————————————————————————————————————————————————————————————
12.void与指针
详见13.c
————————————————————————————————————————————————————————————————————————————————————————————————
13.malloc簇函数
SYNOPSIS
#include <stdlib.h>
void *malloc(size_t size);
向内存申请size个字节,并返回这块内存的首地址
void free(void *ptr);
将ptr所指向的内存区域回收
void *calloc(size_t nmemb, size_t size);
向内存申请nmemb*size个字节,并返回这块内存的首地址
#include<stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
//int *p = malloc(10*sizeof(int));
int *p = (int *)calloc(10,sizeof(int));//会将申请的区域全部清0
int i;
for(i = 0;i < 10;i++)
{
//p[i] = 100+i;
printf("p[%d] = %d\t",i,p[i]);
}
printf("\n");
free(p);//防止内存泄漏(会满)
return 0;
}
月饼是中国人在中秋佳节时吃的一种传统食品,不同地区有许多不同风味的月饼。现给定所有种类月饼的库存量、总售价、以及市场的最大需
求量,请你计算可以获得的最大收益是多少。
注意:销售时允许取出一部分库存。样例给出的情形是这样的:假如我们有3种月饼,其库存量分别为18、15、10万吨,总售价分别为75、
72、45亿元。如果市场的最大需求量只有20万吨,那么我们最大收益策略应该是卖出全部15万吨第2种月饼、以及5万吨第3种月饼,获得
72 + 45/2 = 94.5(亿元)。
输入描述:
每个输入包含1个测试用例。每个测试用例先给出一个不超过1000的正整数N表示月饼的种类数、以及不超过500(以万吨为单位)的正整数
D表示市场最大需求量。随后一行给出N个正数表示每种月饼的库存量(以万吨为单位);最后一行给出N个正数表示每种月饼的总售价(以亿
元为单位)。数字间以空格分隔。
输出描述:
对每组测试用例,在一行中输出最大收益,以亿元为单位并精确到小数点后2位。
输入例子:
3 20
18 15 10
75 72 45
输出例子:
94.50
#include<stdio.h>
int main ()
{
float a[100]={0.0},b[100]={0.0},c[100]={0.0};
int i,N,D,j,k,flag=0;
float t,t1,t2,s1=0,s2,s3;
scanf("%d%d",&N,&D);
for(i=0;i<N;i++)
{
scanf("%f",&a[i]);
}
for(i=0;i<N;i++)
{
scanf("%f",&b[i]);
}
for(i=0;i<N;i++)
{
c[i]=b[i]/a[i];
}
for(i=0;i<N-1;i++)
{
for(j=0;j<N-1-i;j++)
{
if(c[j]<c[j+1])
{
t=c[j];
c[j]=c[j+1];
c[j+1]=t;
t=a[j];
a[j]=a[j+1];
a[j+1]=t;
t=b[j];
b[j]=b[j+1];
b[j+1]=t2;
flag=1;//将月饼单价从大到小顺序排列,其他的库存量,单价利益也跟着 变换。
}
}
if(flag==0)
break;
}
for(i=0;i<N;i++)
{
s1+=a[i];
if(D<s1)
{
k=i;
s2=s1-a[i];
break;
}
}
for(i=0;i<k;i++)
{
s3=0;
s3+=b[i];
}
s3+=(D-s2)*c[k];
printf("最大利益=%.2f\n",s3);
return 0;
}
法二、
#include <stdio.h>
int main()
{
int s,i,j,N;
float tmp,m = 0.0,a[1000],b[1000],c[1000];
scanf("%d%d",&N,&s);
for(i = 0;i < N;i++)
{
scanf("%f",&a[i]);
}
for(i = 0;i < N;i++)
{
scanf("%f",&b[i]);
}
for(i = 0;i < N;i++)
{
c[i] = (b[i]/a[i]);
}
for(j=0;j<N-1;j++)
{
for(i = 0;i < N-j;i++)
{
if(c[i] < c[i+1])
{
tmp = c[i];
c[i] = c[i+1];
c[i+1] = tmp;
tmp = a[i];
a[i] = a[i+1];
a[i+1] = tmp;
}
}
}
printf("%f %f %f",c[0],c[1],c[2]);
for(i = 0;i <= N-1;i++)
{
if(s <= a[i])
{
m += s * c[i];
printf("max= %.2f\n",m);
break;
}
else
{
m += (a[i] * c[i]);
s -= a[i];
}
}
return 0;
}