博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C语言基础学习day08
阅读量:6117 次
发布时间:2019-06-21

本文共 11862 字,大约阅读时间需要 39 分钟。

指针

地址和指针的概念

内存区的每一个字节有一个编号,这就是“地址” 。如果在程序中定义了一个变量,在对程序进行编译时,系统就会给这个变量分配内存单元。

在C语言中,对变量的访问有两种方式,直接访问和间接访问。

 

关于直接访问和间接访问

直接访问如:a=5; 系统在编译时,已经对变量分配了地址,例如,若变量a分配的地址是2000,则该语句的作用就是把常数5保存到地址为2000的单元。

间接访问如:scanf("%d",&a); 调用函数时,把变量a的地址传递给函数scanf,函数首先把该地址保存到一个单元中,然后把从键盘接收的数据通过所存储的地址保存到a变量中。

 

初识指针

在C语言中,指针是一种特殊的变量,它是存放地址的。假设我们定义了一个指针变量 int *i_pointer

用来存放整型变量 i 的地址。 可以通过语句:i_pointer =&i;

 

将i的地址(2000)存放到i_pointer中。这时, i_pointer的值就是(2000) ,即变量i所占用单元的起始地址。

要存取变量i的值,可以采用间接方式:先找到存放“i的地址”的变量i_pointer ,从中取出i的地址(2000),然后取出i的值3。

 

初识两个操作符“*”和“&”

*:叫做取值操作符

&:而这玩意叫做取址操作符

#include
void main(){ int i = 2000; int *pointer; pointer = &i; printf("%d\n", pointer); //打印地址6487572 }
#include
void main(){ int i = 2000; int *pointer; pointer = &i; printf("%d\n", *pointer);//打印这个地址所储存的值2000 }

 

指针和指针变量

知道了一个变量的地址,就可以通过这个地址来访问这个变量,因此,又把变量的地址称为该变量的“指针” 。 指针指的是地址

C语言中可以定义一类特殊的变量,这些变量专门用来存放变量的地址,称为指针变量。

注意:指针变量的值(即指针变量中存放的值)是地址(即指针)。请区分“指针”和“指针变量”这两个概念。

定义指针变量时要注意两点

一、指针变量前面的“*”,表示该变量的类型为指针型变量。

       其一般形式为: 类型说明符 *变量名;

       其中,*表示这是一个指针变量,变量名即为定义的指针变量名,类型说明符表示本指针变量所指向的变量的数据类型。

       例如: float *pointer_1; 指针变量名是pointer_1 ,而不是* pointer_1 

二、在定义指针变量时必须指定基类型。(指针指向变量的类型)

       需要特别注意的是,只有整型变量的地址才能放到指向整型变量的指针变量中。下面的赋值是错误的∶

       float a;

       int * pointer_1;

       pointer_1=&a; /*将float型变量的地址放到指向整型变量的指 针变量中,错误 */

 

指针变量的引用 “&”

请牢记,指针变量中只能存放地址(指针), 不要将一个整数(或任何其他非地址类型的数据)赋给一个指针变量,否则编译器也会把该值当成一个地址来处理。

C语言中提供了地址运算符&来表示变量的地址。 其一般形式为:

 &变量名;

如&a表示变量a的地址,&b表示变量b的地址。当然,变量本身必须预先声明。

#include
void main(){ int a,b; int *pointer_1, *pointer_2; a=100; b=10; pointer_1 = &a; pointer_2 = &b; printf("%d,%d\n",a,b); printf("%d,%d\n",*pointer_1, *pointer_2);}

 

对“&”和“*”运算符再做些说明

如果已执行了语句 pointer_1=&a;

(1)&* pointer_1的含义是什么?

    “&”和“*”两个运算符的优先级别相同,但按自右而左方向结合,因此先进行* pointer_1的运算,它就是变量a,再执行&运算。 因此,&* pointer_1与&a相同,即变量a的地址。

     如果有: pointer_2 =&* pointer_1;

     它的作用是将&a(a的地址)赋给pointer_2 ,如果 pointer_2 原来指向b,经过重新赋值后它已不再指向b了,而指向了a。

     

(2) *&a的含义是什么?

     先进行&a运算,得a的地址,再进行*运算。即&a所指向的变量,也就是变量a。

     *&a和*pointer_1的作用是一样的,它们都等价于变量a。即*&a与a等价。

(3) (*pointer_1)++相当于a++。

       注意括号是必要的,如果没有括号,就成为了*pointer_1++,从附录可知:++和*为同一优先级别,而结合方向为自右而左,因此它相当于*(pointer_1++)。

       由于++在pointer_1的右侧,是“后加”,因此先对pointer_1的原值进行*运算,得到a的值,然后使pointer_1的值改变,这样pointer_1不再指向a了。

 

例题:输入a和b两个整数,按先大后小的顺 序输出a和b。

#include 
void main(){ int *p1, *p2, *p, a, b; scanf("%d %d", &a, &b); p1 = &a; p2 = &b; if( a < b) { p = p1; p1 = p2; p2 = p; } //此后,p1指向b, p2指向a printf("a = %d, b = %d\n", a, b); printf("max = %d, min = %d\n", *p1, *p2);}

输出结果

 

题目:对输入的两个整数按大小顺序输 出!这次用函数实现交换功能!

#include 
void swap(int *p1, int *p2);void main(){ int a, b; int *pointer_1, *pointer_2; scanf("%d %d", &a, &b); pointer_1 = &a; pointer_2 = &b; if(a < b) { swap(pointer_1, pointer_2); //swap实现的是交换…… } printf("\n%d > %d\n", a, b); }void swap(int *p1, int *p2){ int temp; printf("I'm swapping……\n"); printf("Please wait^_^"); temp = *p1; //temp = a; *p1 = *p2; //a = b; *p2 = temp; //b = temp; }

 

数组与指针

一个变量有地址,一个数组包含若干元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址。

指针变量既然可以指向变量,当然也可以指向数组元素(把某一元素的地址放到一个指针变量中)。

所谓数组元素的指针就是数组元素的地址

注意:数组名即“翻译成数组的第一个元素的地址!

例 输出数组中的全部元素

    假设有一个a数组,整型,有10个元素。要输出各元素的值有三种方法:

   (1) 下标法

   (2) 通过数组名计算数组元素地址,找出元素的值。

   (3) 用指针变量指向数组元素

#include 
void main(){ int a[10]; int i; int *p; for( i=0; i < 10; i++ ) { scanf("%d", &a[i]); } printf("\n"); for( p=a; p < (a+10); p++ ) { printf("%d", *p); }}

 

用数组名作函数参数

C语言调用函数时虚实结合的方法都是采用“值传递”方式,当用变量名作为函数参数时传递的是变量的值,当用数组名作为函数参数时,由于数组名代表的是数组首元素地址,因此传递的值是地址,所以要求形参为指针变量。

 

将数组a中n个整数按相反顺序存放

数组名做参数

#include 
void reverse(int x[],int n); /*形参x是数组名*/void main(){ 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"); reverse(a, 10); //作用使得数组重新倒序排放 printf("The array has been inverted:\n"); for( i=0; i < 10; i++) { printf("%d ", a[i]); } printf("\n");}void reverse(int x[], int n) /*形参x是数组名*/{ int temp, i, j, m; m = (n-1)/2; for( i=0; i <= m; i++) { j = n-1-i; //j指向对应的元素 temp = x[i]; x[i] = x[j]; x[j] = temp; } }

指针做参数

#include 
void reserve(int *x, int n); /*形参x为指针变量*/void main(){ 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"); reserve(a, 10); printf("The array has benn inverted:\n"); for( i=0; i < 10; i++) { printf("%d ", a[i]); } printf("\n");}void reserve(int *x, int n) /*形参x为指针变量*/{ int *p, temp, *i, *j, m; m = (n-1)/2; i = x; //i指向数组的第一个元素 j = x-1+n; //j指向的是数组的最后一个元素 p = x+m; //指向中间,配对…… for( ; i <= p; i++, j--) { temp = *i; *i = *j; *j = temp; }}

小结

归纳起来,如果有一个实参数组,想在函数中改变此数组中的元素的值,实参与形参的对应关系有以下4种情况:

(1) 形参和实参都用数组名,如:

void main()

       int a[10];

       … …… f(a,10);

void f(int x[],int n) 

{

..............

}

2) 实参用数组名,形参用指针变量。如:

void main()

{

      int a[10];

      f (a, 10);

}

f (int *a, int n) { …… }

 

(3)实参形参都用指针变量。例如:

void main()

int a[10], *p = a;

f (p , 10); }

void f (int *x, int n) { …… }

 

(4) 实参为指针变量,形参为数组名。如:

void main() { int a[10], *p = a; ……………… f(p,10); }

f (int x[], int n) { ………… }

 

字符串与指针

(1) 用字符数组存放一个字符串,然后输出该字符串。

例题一:定义一个字符数组,对它初始化,然 后输出该字符串。

#include 
void main(){ char string[] = "I love Fishc.com!"; printf("%s\n", string);}

(2) 用字符指针指向一个字符串

例题二:可以不定义字符数组,而定义一个字 符指针。用字符指针指向字符串中的 字符。

#include 
void main(){ char *string = "I love Fishc.com!I love Fishc.com!"; printf("%s\n", string);}
char *string = "I love Fishc.com!";0040D718   mov         dword ptr [ebp-4],offset string "I love Fishc.com!" (00422020)**********************************************************char string[] = "I love Fishc.com!";0040D718   mov         eax,[string "I love Fishc.com!" (00422020)]0040D71D   mov         dword ptr [ebp-14h],eax0040D720   mov         ecx,dword ptr [string "I love Fishc.com!"+4 (00422024)]0040D726   mov         dword ptr [ebp-10h],ecx0040D729   mov         edx,dword ptr [string "I love Fishc.com!"+8 (00422028)]0040D72F   mov         dword ptr [ebp-0Ch],edx0040D732   mov         eax,[string "I love Fishc.com!"+0Ch (0042202c)]0040D737   mov         dword ptr [ebp-8],eax0040D73A   mov         cx,word ptr [string "I love Fishc.com!"+10h (00422030)]0040D741   mov         word ptr [ebp-4],cx***********************************************************char string[] = "I love Fishc.com!I love Fishc.com!";0040D718   mov         ecx,80040D71D   mov         esi,offset string "I love Fishc.com!I love Fishc.co"... (00422fbc)0040D722   lea         edi,[ebp-24h]0040D725   rep movs    dword ptr [edi],dword ptr [esi]0040D727   movs        word ptr [edi],word ptr [esi]0040D729   movs        byte ptr [edi],byte ptr [esi]

 

字符串中字符的存取方法

对字符串中字符的存取,可以用下标方法,也可以用指针方法!

下标法举例:将字符串a复制为字符串b

#include 
void main(){ char a[] = "Fishc.com is a good web site!", b[40]; int i; for(i=0; *(a+i) != '\0'; i++) { *(b+i) = *(a+i); } *(b+i) = '\0'; printf("String a is: %s\n", a); printf("String b is: "); for(i=0; b[i] != '\0'; i++) { printf("%c", b[i]); } printf("\n\n");}

指针方法举例:将字符串a复制为字符串b

#include 
void main(){ char a[] = "Fishc.com is a good web site!", b[40], *p1, *p2; int i; p1 = a; p2 = b; for( ; *p1 != '\0'; p1++, p2++) { *p2 = *p1; } *p2 = '\0'; printf("String a is: %s\n", a); printf("String b is: "); for(i=0; b[i] != '\0'; i++) { printf("%c", b[i]); } printf("\n");}

 

 

指向函数的指针

用函数指针变量调用函数 可以用指针变量指向整型变量、字符串、数组,也可以指向一个函数。

一个函数在编译时被分配给一个入口地址。这个函数的入口地址就称为函数的指针。

/****************************//* 比较a 和 b的大小,求大值 *//****************************/#include 
#if(0)void main(){ int max(int, int); int a, b, c; scanf("%d %d", &a, &b); c = max(a, b); printf("a = %d, b = %d, max = %d\n\n", a, b, c);}#endifint max(int x, int y){ int z; if( x > y ) { z = x; } else { z = y; } return z;}#if(1)//将 main 函数改写为#include
void main(){ int max(int, int); int (*p)(); int a, b, c; p = max; scanf("%d %d", &a, &b); c = (*p)(a, b); printf("a = %d, b = %d, max = %d\n\n", a, b, c);}#endif

 

函数指针变量常用的用途之一是把指针作为参数传递到其他函数。

 

题目: 设一个函数process,在调用它的时候,每次实现不同的功能。(有点类似多态)

输入a和b两个数,第一次调用process时找出a和b中大者,

第二次找出其中小者,

第三次求a与b之和。

/***********************************************************//*  设一个函数process,在调用它的时候,每次实现不同的功能。*//*  输入a和b两个数,第一次调用process时找出a和b中大者,*//*  第二次找出其中小者,第三次求a与b之和。               *//***********************************************************/#include 
void main(){ int max(int, int); /* 函数声明 */ int min(int, int); /* 函数声明 */ int add(int, int); /* 函数声明 */ void process( int, int, int(*fun)() ); /* 函数声明 */ int a, b; printf("Endter a and b: "); scanf("%d %d", &a, &b); printf("max = "); process(a, b, max); printf("min = "); process(a, b, min); printf("sum = "); process(a, b, add);}int max(int x, int y) /* 函数定义 */{ int z; if( x > y ) { z = x; } else { z = y; } return z;}int min(int x, int y) /* 函数定义 */{ int z; if( x < y ) { z = x; } else { z = y; } return z;}int add(int x, int y){ int z; z = x + y; return z;}void process( int x, int y, int(*fun)() ) /* 函数定义 */ { int result; result = (*fun)(x, y); printf("%d\n", result);}

 

 

返回指针值的函数

一个函数可以带回一个整型值、字符值、实型值等,也可以带回指针型的数据,即地址。

其概念与以前类似,只是带回的值的类型是指针类型而已。

这种带回指针值的函数,一般定义形式为 类型名 *函数名(参数表列);

例如: int *a(int x,int y);

例题:有若干个学生的成绩(每个学生有4门课程),要求在用户输入学生序号以后,能输出该学生的全部成绩。用指针函数来实现。

#include 
void main(){ double score[][4] = {
{
60.0, 70.0, 80.5, 90.5}, {
56.0, 89.0, 67.0, 88.0}, {
34.2, 78.5, 90.5, 66.0}}; double *search(double(*pointer)[4], int n); double *p; int i, m; printf("Please enter the number of student: "); scanf("%d", &m); printf("The scores of No.%d are: \n", m); p = search(score, m); for( i=0; i < 4; i++) { printf("%5.2f\t", *(p + i)); } printf("\n\n\n");}double *search(double (*pointer)[4], int n){ double *pt; pt = *(pointer + n); return pt;}

指针函数和函数指针的区别

这两个概念都是简称: 指针函数是指带指针的函数,即本质是一个函数。

函数指针是指向函数的指针变量,因而函数指针本身首先应是指针变量,只不过该指针变量指向函数。

 

指针数组和指向指针的指针

指针数组的概念: 一个数组,若其元素均为指针类型数据,称为指针数组,也就是说,指针数组中的每一个元素都相当于一个指针变量。

一维指针数组的定义形式为 类型名 数组名[数组长度];

例如: int *name[4];

 

有关指针的数据类型的小结

 

指针运算小结

一、指针变量加(减)一个整数 例如:p++、p--、p+i、p-i、p+=i、p-=i等。 指针变量赋值 将一个变量地址赋给一个指针变量。

        如: p=&a; (将变量a的地址赋给p)

                p=array; (将数组array首元素地址赋给p)

                p=&array[i];(将数组array第i个元素 的地址赋给p)

                p=max;(max为已定义的函数,将ma x的入口地址赋给p)

                p1=p2;(p1和p2都是指针变量,将 p2的值赋给p1)

二、指针变量可以有空值,即该指针变量不指向任何变量,可以这样表示:p=NULL;

 

两个指针变量可以相减 如果两个指针变量都指向同一个数组中的元素,则两个指针变量值之差是两个指针之间的元素个数

 

三、两个指针变量比较 若两个指针指向同一个数组的元素,则可以进行比较。指向前面的元素的指针变量“小于”指向后面元素的指针变量。

关于 void类型

void真正发挥的作用在于:

(1) 对函数返回的限定;

(2) 对函数参数的限定。 例如:void abc( void );

 

转载于:https://www.cnblogs.com/yangyuqing/p/10285938.html

你可能感兴趣的文章
Centos 6.x 升级openssh版本
查看>>
公式推♂倒题
查看>>
vue实现点击展开,点击收起
查看>>
如何使frame能居中显示
查看>>
第k小数
查看>>
构建之法阅读笔记三
查看>>
写给对前途迷茫的朋友:五句话定会改变你的人生
查看>>
并行程序设计学习心得1——并行计算机存储
查看>>
JAVA入门到精通-第86讲-半双工/全双工
查看>>
bulk
查看>>
js document.activeElement 获得焦点的元素
查看>>
C++ 迭代器运算
查看>>
【支持iOS11】UITableView左滑删除自定义 - 实现多选项并使用自定义图片
查看>>
day6-if,while,for的快速掌握
查看>>
JavaWeb学习笔记(十四)--JSP语法
查看>>
【算法笔记】多线程斐波那契数列
查看>>
java8函数式编程实例
查看>>
jqgrid滚动条宽度/列显示不全问题
查看>>
在mac OS10.10下安装 cocoapods遇到的一些问题
查看>>
angularjs表达式中的HTML内容,如何不转义,直接表现为html元素
查看>>