c语言_day4

目录

指针

一级指针

指针操作符

初始化

指针运算

1)算术运算

2)关系运算符

指针大小

段错误

易错题目:

指针修饰

const常量化  read  only

void修饰指针  

大小端

二级指针

数组练习题


指针

计算机中以字节为单位,每一个自己都有自己的地址编号。

指针就是地址

查看虚拟机位数:getconf LONG_BIT

32位操作系统

一级指针

指针变量:用来保存地址一个变量

格式:存储类型 数据类型 *指针变量名;

int  a=5;
int	*p=&a;	//定义了一个指针变量p,保存变量a的地址
printf("%p %p\n",&a,p);	//打印结果一样,都是变量a的地址
printf("%d %d\n",a,*p);
//*****************************************
char  b='y';
char  *p=&b;
//注意:数据类型保持一致	

int *p; //p是随机值,是野指针

int *p=NULL; //如果在定义时,指向单纯的定义,可以这么写

指针操作符

&: 取地址符:取变量的地址

*: 取内容:取地址里边的内容

*&a==a: *和&是互逆运算

&*a:错误(运算符优先级)

存储地址的指针本身就是一个变量,所以在内存中也需要空间存储

思考:想知道指针p的地址怎么办? &p

初始化

指针变量在使用前不仅要定义还要初始化,未初始化的指针变量不能随便使用,会产生野指针

1.把普通变量的地址赋值给指针变量

int  a=5;
1)int *p=&a;    //定义指针的同时赋值
2)int *p=NULL;
    p=&a;        //先定义后赋值

p是变量a的地址,而*p又可以取到地址里边的内容

通过*p改变指针指向的内容

*p = 8;
printf("%d %d\n",*p,a);

  2.把数组的首地址赋值给指针变量

char a[]="abcd";
char *p=a;    //指针指向数组的首地址,'a'
printf("%s %s\n",a,p);
printf("%c\n",*p);

 3.把指针变量里边保存的地址赋值给另一个指针变量

float a=2.5;
float *p=&a;
float *q=p;//&a==p
*q=888.8;
printf("%.1f %.1f %.1f\n",a,*p,*q);

p++;//p指针变量,可以被赋值

注意:a++;//错误   a是地址常量,不能被赋值,不能为左值(=左边)

注意:定义的指针类型要与它所要指向的数据的类型一致;指针类型就是进行指针运算时其移动的位数

示例:

#include<stdio.h>
int main()
{
	char a[6]="hello";
	int *p=a;
	printf("%c",*(p+1));
	return 0;
}
//运行结果:o

指针运算

1)算术运算
char a[]="hello";
char *p=a;
printf("%c %p\n",*p,p);
p++;//p=p+1
printf("%c %p\n",*p,p);

int a[]={2,13,4,5};
    int *p=a;
    printf("%d %p\n",*p,p);
    p++;
    printf("%d %p\n",*p,p);

p++://指针向高地址方向移动一个数据单位(char 移动1字节,int移动4字节),指针的指向发生改变
p--://指针向低地址方向移动一个数据单位(char 移动1字节,int移动4字节),指针的指向发生改变
int a[]={2,13,4,5};
    int *p=a;
    i8nt *q=&a[2];
    printf("%d %p\n",*q,q);
    q--;
    printf("%d %p\n",*q,q);

p+n:访问高地址方向第n个数据的地址,指针的指向不发生改变

p-n:访问低地址方向第n个数据的地址,指针的指向不发生改变

p++://指针向高地址方向移动一个数据单位(char 移动1字节,int移动4字节),指针的指向发生改变

p--://指针向低地址方向移动一个数据单位(char 移动1字节,int移动4字节),指针的指向发生改变

p++相当于p=p+1,p被重新赋值

p+2没有改变p的值,没有对p重新赋值

注意:两个地址之间的差值=两个地址之间相隔的元素个数

例:

int m = 100;
double n = 200;
int *p=NULL;
double *q=NULL;
p= &m;
q = &n;
printf(“m=%d &m=%p\n”, m, &m);   
printf(“p=%p p+2=%p\n”, p, p+2);   
printf(“n=%lf &n=%p\n”, n, &n);  
printf(“q=%p q+2=%p\n”, q, q+2); 

练习:

char s[32]="hello";
char *p=s;
p++;
char y=*--p;
printf("%c",y);	//h

char a[ ]="interesting" , *p ;
p=a ;
while (*p!='s') { printf(“%c”,*p-32); p++ ; }
A)INTERESTING  B)INTERESter  C)INTEREster  D)INTERE
//答案:D

2)关系运算符

> <   ==     !=地址大的大于地址小的

指针之间进行关系运算,比较的是他指向的地址的高低

char  a[]="hello";
char  *p=a,*q=&a[2];
if(q>p)
	printf("hahaha\n");

注意:指针指向同一个数组

练习:

int a[5]={10,20,30};
int *p=a;
printf("%d\n",++*p);    //11
printf("%d\n",*p);    //11
                //a[5]={11,20,30};
p = a;
printf("%d\n",(*p)++);    //11
printf("%d\n",*p);        //12
                            //a[5]={12,20,30};
p=a+1;
printf("%d\n",*p++);    //20
printf("%d\n",*p);        //30
                    //a[5]={12,20,30};
p=a+1;
printf("%d\n",*++p);    //30
printf("%d\n",*p);        //30

思考:指针的大小是多少

易错题:

下面程序的输出结果是什么?

思路:

*(p++)+=100;//*p=*p+100;*p++;

printf("%d %d\n",*p,*(++p)); //printf打印多个参数,从右向左依次执行能够改变变量值的式子,会直接把改变后的变量带入。带入完毕后再从左往右依次输出

指针大小

   int a=2;
    int *p1=&a;
    printf("%d\n",sizeof(p1));	//4
    char b='q';
    char *p2=&b;
    printf("%d\n",sizeof(p2));	//4
    short c=2;
    short *p3=&c;
    printf("%d\n",sizeof(p3));	//4

打印结构都是4,原因:

指针的大小取决于操作系统

32位操作系统,指针大小为4

64位操作系统,指针大小为8

32位:单次运算能处理的最大数据位数

可以用8位16进制表示0x123...;1位16进制=4位2进制   32位=4字节

段错误

Segmentation fault (core dumped)

指针虽然灵活好用但是用不好会出现段错误。出现的原因有:访问不存在的内存地址访问系统保护的内存地址 、修改只读的内存地址的内容、空指针废弃 (eg:malloc与free释放后,继续使用) 、堆栈溢出内存越界 (数组越界)

访问不存在的内存地址
int *p=NULL;
    *p=0;
访问系统保护的内存地址
int *p=(int *)8;
    *p=99;
修改只读的内存地址的内容
char *p="world";
    *p='h';
空指针废弃
int *p=NULL;
printf("%d\n",*p);
内存越界 (数组越界)
char a[3]={};
printf("%c\n",a[99999999]);

练习:

1.字符串char  s[]="234",printf(%d\n",num);//234

2.编写一个程序实现功能:将字符串“Computer Science”赋值给一个字符数组,然后从第一个字母开始间隔的输出该字符串,用指针完成。结果:Cmue cec

3.字符串倒置(用指针实现)    如:hello->olleh

定义两个指针分别指向字符串的开头和结尾,前面的指针向后走,后面的指针向前走

易错题目:

1.

#include<stdio.h>
int main()
{
	char s[32]="hello";
	char *p=s;
	p++;
	char y=(*--p)++;
	printf("%c",y);
	return 0;
}

运行结果:h;

2.

3.

注意:

1.--*p;    是对p指向的内容

2.(*p)++;    最后是对p指向的内容++

3.*p++;是先算p++,再计算*。(单目运算符的运算顺序是自右向左);

总结

在输出或者赋值语句中:

*p++:先取内容,再移动指针的指向(向高地址方向移动一个数据单位)

(*p)++:先取内容*p ,再对内容+1

++*p:先取内容*p, 在对内容+1

++(*p):先取内容*p, 在对内容+1

练习:

1.给定一串字符"I love china",实现以单词为单位的逆序,如:"china love i"

解答:

思路:可以先全部倒过来:anihc evol i,然后再把每个单词倒过来---- 根据空格确定单词--空格既是一个单词的开头又是一个单词的结尾

示例:

char a[]="i love china",t;
char *p=a;				//p:指向开头
char *q=p+strlen(a)-1;	//q:指向结尾
    char *k=NULL;		//k:空格
    while(p<q)
    {
        t=*p;
        *p=*q;
        *q=t;
        p++;
        q--;
    }						//全部倒置
    puts(a);

p=q=a;			//都指向开头
    while(*p)
    {
			while(*p=='  ')	//针对于从第二个单词开始,找单词开头
				p++;	
			q=p;		//从当前的单次开始去找结尾
     			while(!q='  '&&*q!='\0')
q++;
k=q;	//循环外部,此时q指向空格
q--;   	
while(p<q)
{
	t=*p;
     *p=*q;
     *q=t;
	p++;

指针修饰

const常量化  read  only

 (1)const修饰变量,变量的值不能通过变量名进行修改

const int a=5;	// int  const a=5;
 a++;	//错误

    通过指针修改变量的值

int *p=&a;
*p=50;	//可以

(2)修饰指针  *p   指针指向的内容不能修改,指针的指向可以修改

int a=5;
const int *p=&a;		//修饰*p  指针指向的内容不能修改,指针的指向可以修改
*p=50;		//错误

int b=50;
p=&b;
printf("%d\n",*p);	//正确

(3)修饰p  指针的指向不能修改,指针指向的内容可以修改

int a=5;
int * const p=&a;
int b=50;
p=&b;	//错误
************************************
*p=666;	//正确

//指针的指向不能改,指针指向的内容也不能改

int a=5;
int const * const p=&a;

练习:

 写出下面的声明:

(1) 指向常整形数的指针(整形数是不可修改的,但指针可以)

______________________________________________________________

(2)指向整型数的常指针(指针指向的整型数是可以修改的,但指针是不可修改的

void修饰指针  

void  a; //错误

void  *p;//p是任意类型的指针  后期使用时,需要强转

强转指针:(int *)p 取内容:*((int *)p)

int a=5;
void *p=NULL;
p=&a;
printf("%p %d\n",(int *)p,*((int *)p));	//强转只是当时变了
//*********************************************************
int a=5;
void *p=NULL;
int *q=(int *)p;
q=&a;

大小端

大端:低地址存放高字节数据,高地址存放低字节数据

小端:低地址存放低字节数据,高地址存放高字节数据

举例:存储数据0x12345678,起始地址0x1000

0x1000 0x1001 0x1002 0x1003

大端:0x12 34 56 78

小端:0x78 56 34 12

int a=0x12345678;
    char b;
    b=(char)a;
    printf("%x\n",b);//78

练习:

1.

(注意,第5行应该是a[6])

2.

3.已知字符数组a[10]b[10]中元素的值递增有序,用指针实现将两个数组中元素按照递增顺序输出。

示例:

二级指针

一级指针:存放变量的地址

二级指针:存放一级指针的地址

格式:存储类型 数据类型 **指针变量名

int a=5;
int *p=&a;
int **q=&p;

q=&p
*q=*&p=p  =&a		*q=p=&a
**q=*p=*&a=a		**q=*p=a

访问a的值:a   *p   **q

访问a的地址:&a    p    *q

访问p的地址:&p   q

数组练习题

1.若有以下说明语句:int a[12]={1,2,3,4,5,6,7,8,9,10,11,12};char c=’a’,d,g;则数值为4的表达式是()。

A)a[g-c] B)a[4] C)a[‘d’-‘c’] D)a[‘d’-c]

2.假设int型变量占两个字节的存储单元,若有定义:int x[10]={0,2,4};则数组x在内存中所占字节数为()。

A)40 B)6 C)12 D)20

3.下列合法的数组定义是()。

A)int a[]=”string”; B)int a[5]={0,1,2,3,4,5};

C)char a=”string”; D)char a[]={0,1,2,3,4,5};

4.若给出定义:char x[]=”abcdefg”;char y[]={‘a’,’b’,’c’,’d’,’e’,’f’,’g’};则正确的叙述为()。

A)数组x和数组y等价 B)数组x和数组y的长度相同

C)数组x的长度大于数组y的长度    D)数组y的长度大于数组x的长度

5.下列程序运行后的输出结果是()。

#include<stdio.h>

int main()

{

int n[3],t,j,k;

for(t=0;t<3;t++)

n[t]=0;

    k=2;

    for(t=0;t<k;t++)

for(j=0;j<3;j++)

n[j]=n[t]+1;

printf("%d\n",n[1]);

}

A)2 B)1 C)0 D)3

6.有以下程序,执行后输出结果是()。

#include<stdio.h>

int main()

{

int p[7]={11,13,14,15,16,17,18}, i=0,k=0;

while(i<7 && p[i]%2)

{

k =k+ p[i];                    

i++;

}

printf("%d\n", k);

}

A)58 B)56 C)45 D)24

7.有以下程序,执行后输出结果是()。

#include<stdio.h>

int main()

{

int m[][3]={1,4,7,2,5,8,3,6,9};

int i,j,k=2;

for(i=0; i<3; i++)

{

printf("%d ",m[k][i]);

}

}

A)4 5 6 B)2 5 8 C)3 6 9         D)7 8 9

8.以下能正确定义一维数组的选项是()。

A)int num[];                 B) #define N 100

int num[N];

C)int num[0..100];            D) int N=100;

int num[N];

9、有以下程序,执行后输出结果是()。

#include<stdio.h>

int main( )

{  

char a[]="abcdefg",b[10]="abcdefg";

    printf("%d  %d\n",sizeof(a),sizeof(b));

A)7  10 B)8 8 C)8 10 D)10 10

 

10、若有以下定义语句:char s[10];s=”abcd”;printf(“%s\n”,s);则运行结果是()。

A)输出abcd        B)输出a           C)输出ab cd        D)编译不通过

11.不能把字符串“Hello!”赋给数组b的语句是()。

A)char b[10]={‘H’,’e’,’l’,’l’,’o’,’!’};

B)char b[10];b=”Hello!”;

C)char b[10]; strcpy(b,”Hello!”);            

D)char b[10]=”Hello!”;

 

12、若有以下程序段,该程序段的输出结果是()。   

char str[]=“a b \n \012 \\ \” ”;

printf(“%d”,strlen(str));

A)3               B)4               C)6              D)12

13.下列程序的输出结果是()。

 #include <stdio.h>

main()

{

char ch[7]={"65ab21"};

int j,s=0;

for(j=0;ch[j]>='0'&&ch[j]<='9';j+=2)

s=10*s+ch[j]-'0';

printf("%d\n",s);

}

A)12ba56         B)66521       C)6         D)62

14.设已定义char a[10]和 int j,则下面输入函数调用中错误的是()。

A)scanf(“%s”,a);                B)for(j=0;j<9;j++) scanf(“%c”,a[j]);

C)gets(a);                       D)for(j=0;j<9;j++) scanf(“%c”,&a[j]);

 

15、设已定义char x[8]和int j,为了给该数组赋值,下面语句中正确的是()。

A)x[8]=”Turbo C”;               B)x=” Turbo C”;

C)x[]=”Turbo C”;                D)for(j=0;j<7;j++) x[j]=getchar();

16.有如下程序,该程序的输出结果是()。

#include <stdio.h>

main()

{

int n[5]={0,0,0},j,k=2;

for(j=0;j<k;j++)

n[j]=n[j]+1;

printf("%d\n",n[k]);

}

A)不确定的值 B)2 C)1 D)0

17.写出下列成绩的输出结果:————————

#include <stdio.h>

void main()

{

    int m[] = {1,2,3,4,5,6,7,8,9},i,j,k;

    for(i=0;i<4;i++) //0 1 2 3

    {

        k=m[i];

        m[i]=m[8-i];

        m[8-i]=k;

        for(j=o;j<9;j++)

            printf("%d", m[j]);

        putchar('\n');

    }

}

18.有数组定义 int niNumberA[100]; 以下叙述不正确的是(   )。(山大华天)

A. 数组 niNumberA 有100个元素

B. 数组 niNumberA 的最后一个元素是 niNumberA[100]

C. 数组 niNumberA 的第一个元素 *niNumberA

D. 数组 niNumberA 的字节数是 sizeof(int)*100

19.以下不能对二维数组 a 进行正确初始化的语句是 (  )。(山大华天)

A. int A[2][3] = {0};

B. int B[][3] = {{0, 1}, {0}};

C. int C[2][3] = {{0, 1}, {2, 3}, {4, 5}};

D. int D[][3] = {0, 1, 2, 3, 4, 5};

20. 下列对 C 语言字符数组的描述中错误的是 (  )  (鲁科安全)

A. 字符数组可以存放字符串

B. 字符数组中的字符串可以整体输入、输出

C. 不可以用关系运算符对字符数组中的字符串进行比较

D. 可以在赋值语句中通过赋值运算符 "=" 对字符数组整体赋值

答案:

  1. D 2.D 3.D 4.C 5.D 6.D 7.C 8.B 9.C 10.D 11.B 12.C 13.C 14.B 15.D 16.17.923456781

983456721

987456321

987654321

 18.B 19.C 20.D

  • 19
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值