【实验5】数组和指针


实验任务一

实验源代码:

 1 #include <stdio.h> 
 2 
 3 const int N=3;
 4 int main() {
 5     int a[N] = {1, 2, 3};  
 6     int i;
 7     
 8     printf("通过数组名及下标直接访问数组元素:
");
 9     for(i=0; i<N; i++)
10         printf("%d: %d
", &a[i], a[i]);
11         
12     printf("通过地址间接访问数组元素:
");
13     for(i=0; i<N; i++)
14         printf("%d: %d
", a+i, *(a+i));
15 
16     return 0;
17 } 

运行结果:

有关问题:

1. 数组元素在内存中是否是连续存放的?

  答:是的,并且在整型数组中间隔四个字节。

2. 对于数组元素及其地址的访问,以下访问方式是否是等价的?

   a+i和&a[i]都表示数组元素a[i]的地址

  *(a+i)和a[i]都表示数组元素a[i]

  答:是的。


实验任务二:

程序源代码:

 1 #include <stdio.h>
 2 const int LINE = 2;
 3 const int COL = 3;
 4 
 5 int main() {
 6     int a[LINE][COL] = {1,2,3,4,5,6};  
 7     int i,j;
 8     
 9     printf("通过数组名及下标直接访问数组元素:
");
10     for(i=0; i<LINE; i++)
11         for(j=0; j<COL; j++)
12             printf("%d: %d
", &a[i][j], a[i][j]);
13         
14     printf("通过地址间接访问数组元素:
");
15     for(i=0; i<LINE; i++)
16         for(j=0; j<COL; j++)
17             printf("%d: %d
", a[i]+j, *(a[i]+j));
18     
19     printf("二维地址中a+i表示的地址:
");
20     for(i=0; i<LINE; i++) 
21         printf("a + %d: %d
", i, a+i);
22     
23     return 0;
24 } 

运行结果:

回答问题:

1. c语言中,二维数组在内存中是否是按行存放的?

  答:是的,并且行的顺序优先于列。

2. 对于二维数组元素及其地址的访问,以下方式是否是等价的?

  a[i]+j和&a[i][j]都表示二维数组元素a[i][j]的地址

  *(a[i]+j)和a[i][j]都表示二维数组元素a[i][j]

  答:是的。

3. 对于二维数组a[2][3],以下方式是否是等价的?

  a和&a[0]都表示二维数组第0行的地址

  a+1和&a[1]都表示二维数组第1行的地址

  答:是的。


实验任务三:

程序源代码:

 1 // 使用指针变量间接访问一维数组 
 2 #include <stdio.h> 
 3 #include <stdlib.h> 
 4 
 5 const int N=3;
 6 
 7 int main() {
 8     int a[N];
 9     int *p,i;
10     
11     // 通过指针变量p,完成数组元素输入
12     for(p=a; p<a+N; p++)
13         scanf("%d", p);
14     
15     // 过指针变量p,完成数组元素输出
16     for(p=a; p<a+N; p++)
17         printf("%d ", *p);
18     printf("
");
19     
20     p = a;
21     //通过指针变量p,完成数组元素输入
22     for(i=0; i<N; i++)
23         scanf("%d", p+i); 
24         
25     // 通过指针变量p,完成数组元素输出
26     for(i=0; i<N; i++)
27         printf("%d ", *(p+i));
28     printf("
"); 
29 
30     return 0;
31 }  

运行结果:

回答问题:

1. 程序中,指针变量p在使用时是否指向确定的地址?

  答:是的。在使用时都指向了数组a中的元素的地址。

2. 程序源码中,line12-line13执行完后,指针变量p指向哪里?line16-line17执行完后,指针变量p 指向哪里?

  答:a[3]; a[3]。

3. 程序源码中,line22-line27执行完后,指针变量p指向哪里?line26-line27执行完后,指针变量p 指向哪里?

  答:a[3]; a[3]。

4. 对比line16-line17和line26-line27,体会它们通过指针变量间接访问一维数组时的差异和灵活性。

  答:一个是直接改变指针变量p的指向(l16-l17),另一个是不改变指针变量p的指向的情况下,在输出时改变要输出变量的地址(l26-l27)。


实验任务四:

程序源代码:

 1 // 使用指针变量间接访问二维数组 
 2 #include <stdio.h> 
 3 
 4 int main() {
 5     int a[2][3] = {1,2,3,4,5,6};
 6     int i,j;
 7     int *p;  // p是指针变量,存放int型数据的地址 
 8     int (*q)[3]; // q是指针变量,存放包含有3个元素的一维数组的地址
 9     
10     // 通过指针变量p间接访问,输出二维数组a的元素值
11     for(p=a[0]; p<a[0]+6; p++)
12         printf("%d ", *p);
13     printf("
");
14     
15     // 通过行指针变量q间接访问,输出二维数组a的元素值 
16     for(q=a; q<a+2; q++)
17         for(j=0; j<3; j++)
18             printf("%d ", *(*q+j));
19     printf("
");
20     
21 
22     return 0;
23 }  

运行结果:

回答问题:

1. 程序源码中,line11改成如下形式是否可以?

11  for(p=&a[0][0]; p<&a[0][0] + 6; p++)

  答:可以,都是访问了二维数组a0行中列元素的地址。

2. 程序源码中,line18中,*q+j和*(*q+j)分别表示什么?

  答:*q+j代表指针q指向的整型数组变量a[0]的地址后整型变量j的值个单元的地址。

    *(*q+j)代表上述地址所存放的整型变量。

3. 结合line11-line12和line16-line18,理解和体会二维数组中,指向数组元素的指针变量p和指向一维数组的指针变量q的不同。

  答:指针p所指向的变量是二维整型数组a中的列元素,并逐个输出。

    指针q所指向的变量是二维整型数组a中的行元素,再在输出时将指针指向的行元素中的列元素逐个输出。

4. 基于对这个实验的理解,回答以下问题。

1 int a[2][3];
2 int (*q)[3];
3 int *p;
4 
5 p = a[0];
6 q = a;

则,以下能够正确表示数组元素a[1][2]地址的有?

A. &a[1][2]

B. a[0] + 5

C. p + 5

D. *q + 5

E. *(q+1) + 2

F. &a[0][0] + 1*3 + 2

G. a[0] + 1*3 + 2  

  答:A||B||C||D||E||F||G


实验任务五:

Q1:

补足后的程序源代码:

 1 // 练习:使用二分查找,在一组有序元素中查找数据项
 2 //  形参是数组,实参是数组名 
 3 #include  <stdio.h>
 4 
 5 const int N=5;
 6 
 7 int binarySearch(int x[], int n, int item); // 函数声明 
 8 
 9 int main() {
10     int a[N]={2,7,19,45,66};
11     int i,index, key;
12     
13     printf("数组a中的数据:
");
14     for(i=0;i<N;i++)
15        printf("%d ",a[i]);
16     printf("
");
17     
18     printf("输入待查找的数据项: ");
19     scanf("%d", &key);
20     
21     // 调用函数binarySearch()在数组a中查找指定数据项key,并返回查找结果给index
22     index=binarySearch(a,N,key);// 补足代码① 
23     // ×××
24     
25     if(index>=0) 
26         printf("%d在数组中,下标为%d
", key, index);
27     else
28         printf("%d不在数组中
", key); 
29    
30    return 0;
31 }
32 
33 //函数功能描述:
34 //使用二分查找算法在数组x中查找特定值item,数组x大小为n 
35 // 如果找到,返回其下标 
36 // 如果没找到,返回-1 
37 int binarySearch(int x[], int n, int item) {
38     int low, high, mid;
39     
40     low = 0;
41     high = n-1;
42     
43     while(low <= high) {
44         mid = (low+high)/2;
45         
46         if (x[mid]==item/*补足代码②*/)
47             return mid;
48         else if(x[mid]>item/*补足代码③*/)
49             high = mid - 1;
50         else
51             low = mid + 1;
52     }
53     
54     return -1;
55 }

运行结果:

Q2:

补足后的程序源代码:

 1 // 练习:使用二分查找,在一组有序元素中查找数据项
 2 //  形参是指针变量,实参是数组名 
 3 #include  <stdio.h>
 4 
 5 const int N=5;
 6 
 7 int binarySearch(int *x, int n, int item); // 函数声明 
 8 
 9 int main() {
10     int a[N]={2,7,19,45,66};
11     int i,index, key;
12     
13     printf("数组a中的数据:
");
14     for(i=0;i<N;i++)
15        printf("%d ",a[i]);
16     printf("
");
17     
18     printf("输入待查找的数据项: ");
19     scanf("%d", &key);
20     
21     // 调用函数binarySearch()在数组a中查找指定数据项key,并返回查找结果给index
22     index=binarySearch(a,N,key); // 补足代码① 
23     // ×××
24     
25     if(index>=0) 
26         printf("%d在数组中,下标为%d
", key, index);
27     else
28         printf("%d不在数组中
", key); 
29    
30    return 0;
31 }
32 
33 //函数功能描述:
34 //使用二分查找算法在从x中查找特定值item,数组x大小为n 
35 // 如果找到,返回其下标 
36 // 如果没找到,返回-1 
37 int binarySearch(int *x, int n, int item) {
38     int low, high, mid;
39     
40     low = 0;
41     high = n-1;
42     
43     while(low <= high) {
44         mid = (low+high)/2;
45         
46         if ( item == *(x+mid) )
47             /*补足代码②*/
48             return mid; 
49         else if(item < *(x+mid))
50             /*补足代码③*/
51             high = mid-1; 
52         else
53             /*补足代码③*/
54             low = mid+1; 
55     }
56     
57     return -1;
58 }

运行结果:


实验任务六:

补充后的程序源代码:


 1 // 练习:使用选择法对字符串按字典序排序
 2 #include <stdio.h>
 3 #include<string.h>
 4 const int N = 5;
 5 
 6 void selectSort(char str[][20], int n ); // 函数声明,形参str是二维数组名 
 7 int main() {
 8     char name[][20] = {"Bob", "Bill", "Joseph", "Taylor", "George"};
 9     int i;
10     
11     printf("输出初始名单:
");
12     for(i=0; i<N; i++)
13         printf("%s
", name[i]);
14         
15     selectSort(name, N);  // 调用选择法对name数组中的字符串排序
16     
17     printf("按字典序输出名单:
");
18     for(i=0; i<N; i++)
19         printf("%s
", name[i]);
20     
21     return 0;
22 } 
23 
24 // 函数定义
25 // 函数功能描述:使用选择法对二维数组str中的n个字符串按字典序排序 
26 void selectSort(char str[][20], int n) {
27     int i,j,t,k;
28     char temp[20];
29     for(i=0; i<n; i++){
30         k = i;
31         for(j=i+1; j<n; j++){ 
32             for(t=0; t<20; t++){
33                 if(str[j][t]==str[k][t])
34                     continue;
35                 if(str[j][t]<str[k][t])
36                     k = j;
37                 else
38                     break;
39             }
40         }
41         if(str[k] != str[i]){
42             strcpy(temp,str[i]);
43             strcpy(str[i],str[k]);
44             strcpy(str[k],temp);
45         }
46     }
47     // 补足代码
48     // ××× 
49 }


 

运行结果:



实验总结:

1.第一次充分地实践了新学的指针,它成为了我的新助手,我必须要惯用它。

  但我最重要的发现是在实验里没有体现的:指针可以把实参形参建立起联系。例如在互换两个整型变量的值的void函数中,形参为int是无法直接交换二者并且返回的。这就需要指针,或者叫地址。

  我习惯把指针认为是地址,所以我这么说。在调用时不是以整型变量为实参,而是以其地址为实参,再通过函数交换二者的地址,就做到了交换。原来完全无法解决的函数问题通过指针的方法,我解决了。

2.目前初学指针,虽没有体会但我明白其有着强大的功能。是有待我日后去发现的。

  曾有言指针是初学者的地狱,是黑客的天堂。它可以访问内存中不能直接访问的内容,而又是相当危险的(这也应证了C语言相比其他语言而言是一门危险的编程语言)。

3.不懂的地方需要立刻实践,生硬的地方就得多打。这是初学程序员的准则,私以为。


Thanks for reading.

原文地址:https://www.cnblogs.com/yinjx/p/14111577.html