C程序设计 07-09 数组和指针(二)

折半查找法(二分查找)

折半搜索(half-interval search),也称二分搜索(英语:binary search)、对数搜索(英语:logarithmic search),是一种在有序数组中查找某一特定元素的搜索算法。

搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。

算法实现 :

 
  1. int Binarserach(int *arr,int len,int key)

  2. {

  3. int low = 0;

  4. int high = len-1;

  5. while(low <= high)

  6. {

  7. int mid = (low+high) >> 1; //相当于(low+high)/2;

  8. if(arr[mid] == key)

  9. {

  10. return mid;

  11. }

  12. else if(arr[mid] > key)

  13. {

  14. high = mid-1;

  15. }

  16. else

  17. {

  18. low = mid+1;

  19. }

  20. }

  21. return -1;

  22. }

字符串处理函数的算法实现

1、strcpy() —— 字符串复制函数

 
  1. char *My_strcpy(char *dest,char *src)

  2. {

  3. char *p = dest;

  4. while(*dest++ = *src++){}

  5. return p;

  6. }

2、strncpy() —— 字符串复制函数(复制n个字符)

 
  1. char *My_strncpy(char *dest,char *src,int n)

  2. {

  3. assert(dest != NULL && src != NULL);

  4. assert(n > 0 && n < strlen(src));

  5. char *p = dest;

  6. for(int i=0;i<n;i++)

  7. {

  8. *dest++ = *src++;

  9. }

  10. return p;

  11. }

3、atoi() —— " 字符串-->整型 "转换函数

 
  1. char *My_atoi(char *str)

  2. {

  3. assert(str != NULL);

  4. int num = 0;

  5. while (*str == ' ')

  6. {

  7. str++;

  8. }

  9. while (*str == '-')

  10. {

  11. printf("-");

  12. str++;

  13. }

  14. while(isdigit(*str))

  15. {

  16. num = num * 10 + (*str++) -'0';

  17. return num;

  18. }

  19. }

4、itoa() —— " 整型 -->字符串 "转换函数

 
  1. char *My_itoa(char *str,int num)

  2. {

  3. assert(str != NULL);

  4. int i = 0;

  5. while (num != 0)

  6. {

  7. str[i] = num % 10 + '0';

  8. num /= 10;

  9. i++;

  10. }

  11. str[i] = '\0';

  12. i--;

  13. for(int j=0;j<i;j++,i--)

  14. {

  15. char ch = str[i];

  16. str[i] = str[j];

  17. str[j] = ch;

  18. }

  19. return str;

  20. }

5、strcat() —— 字符串连接函数

 
  1. char *My_strcat(char *dest,char *src,int len)

  2. {

  3. assert(dest != NULL && src != NULL);

  4. assert(strlen(dest) + strlen(src) > len);

  5. char *p = dest;

  6. while(*dest != '\0')

  7. {

  8. dest++;

  9. }

  10. while(*dest == *src){}

  11. return p;

  12. }

6、strcmp() —— 字符串比较函数

 
  1. int My_strcmp(char *str1,char *str2)

  2. {

  3. assert(str1 != NULL && str2 != NULL);

  4. while (*str1 == *str2 && *str2!='\0')

  5. {

  6. str1++;

  7. str2++;

  8. }

  9. if(*str1 > *str2)

  10. {

  11. return 1;

  12. }

  13. else if(*str1 < *str2)

  14. {

  15. return -1;

  16. }

  17. else

  18. {

  19. return 0;

  20. }

  21. }

数组指针与指针数组

数组指针(也称行指针)
数组指针:数组指针可以说成是”数组的指针”,首先这个变量是一个指针,其次,”数组”修饰这个指针,意思是说这个指针存放着一个数组的首地址,或者说这个指针指向一个数组的首地址
定义:int (*p)[n];
()优先级高,首先说明p是一个指针指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。

如要将二维数组赋给一指针,应这样赋值:
int a[3][4]; 
int (*p)[4];     //该语句是定义一个数组指针,指向含4个元素的一维数组。
 p=a;            //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0]
 p++;            //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]

所以数组指针也称指向一维数组的指针,亦称行指针

指针数组

指针数组:指针数组可以说成是”指针的数组”,首先这个变量是一个数组,其次,”指针”修饰这个数组,意思是说这个数组的所有元素都是指针类型,在32位系统中,指针占四个字节。
定义:int *p[n];
[]优先级高,先与p结合成为一个数组,再由 int * 说明这是一个整型指针数组它有n个指针类型的数组元素。这里执行p+1时,则p指向下一个数组元素(后面会详细讲),这样赋值是错误的:p=a;因为p是个不可知的表示,只存在p[0]、p[1]、p[2]...p[n-1],而且它们分别是指针变量可以用来存放变量地址。但可以这样 *p=a; 这里*p表示指针数组第一个元素的值,a的首地址的值。

首先先定义一个指针数组,既然是数组,名字就叫arr;

 
  1. char *arr[4] = {"hello", "world", "shannxi", "xian"};

  2. /*arr就是定义的一个指针数组,它有四个元素,

  3. 每个元素是一个char *类型的指针,这些指针存放着其对应字符串的首地址。

  4. 这个指针数组有多大呢?答案是16个字节,因为它是一个指针数组。 */

内存映像图:

内存分区模型

  • 栈区:局部变量、局部常量
  • 堆区:程序员自我申请和释放的内存
  • 全局区:全局变量、静态变量、全局常量、字符串常量
  • 代码区:存代码

常量分为:全局常量、字符串常量(全局区)和局部常量(栈区)
一般情况下,从栈区到代码区,是从高地址到低地址。栈向下增长,堆向上增长。

arr[4]是一个在主函数定义的数组。把它对应到对应到内存中,arr是一个在栈区,有四个元素的数组,而每一个数组又是一个指针,所以说它的四个元素各占四个字节,所以变量arr的大小是16个字节

初始化arr的{“hello”, “world”, “shannxi”, “xian”};的是什么?
它们也存在在内存中,只是跟arr这个变量不在同一段空间,它们被分配在只读数据区,数组arr[4]的四个指针元素,分别存放着这四个字符串的首地址,想象一下,从栈区有四只无形的手指向数据区的空间。arr+1会跳过四个字节,也就是一个指针的大小
这就相当与定义char *p1 = “hello”,char *p1 = “world”,char *p3 = “shannxi”, char *p4 = “xian”,这是四个指针,每个指针存放一个字符串首地址,然后用arr[4]这个数组分别存放这四个指针,就形成了指针数组。

 区别:

数组指针只是一个指针变量,似乎是C语言里专门用来指向二维数组的,它占有内存中一个指针的存储空间

指针数组是多个指针变量,以数组形式存在内存当中,占有多个指针的存储空间

还需要说明的一点就是,同时用来指向二维数组时,其引用和用数组名引用都是一样的。
比如要表示数组中 i 行 j 列一个元素:*(p[i]+j)、*(*(p+i)+j)、p[i][j]、(*(p+i))[j]。优先级:() > [] > *

二维数组

一个二维数组,在本质上,是一个一维数组的列表。声明一个 x 行 y 列的二维整型数组,形式如下:

type arrayName [ x ][ y ];

type 可以是任意有效的 C 数据类型,arrayName 是一个有效的 C 标识符。一个二维数组可以被认为是一个带有 x 行和 y 列的表格。下面是一个二维数组,包含 3 行和 4 列:

C 中的二维数组

初始化二维数组

 
  1. int arr[2][3]={{1,2,3},{4,5,6}}; // 初始化1

  2. //int brr[2][3]=arr // 错误,数组是聚合类型,初始化只有一次机会,不能整体赋值

  3. int arr[2][3]={1,2,3,4,5,6}; // 初始化2

  4. int arr[2][3]={}; // 初始化3,数组中元素全为0

  5. int arr[2][3]={0}; // 初始化4,和初始化3效果相同

  6. int arr[2][3]; //初始化5,arr5数组中存放随机值

  7. int arr[][3]={1,2,3,4,5,6}; // 初始化6,正确,行数可省略

  8. //int arr[2][]={1,2,3,4,5,6}; //错误,编译器不会确定列数,列数不可省略

  9. int arr7[][3]={1,2,3}; // 初始化7,其余数组元素为0

补充

 
  1. int brr[2][3] = {1,2,3,4,5,6};

  2. printf("%d <== brr\n",brr); //数组首元素的首地址

  3. printf("%d <== brr+1\n",brr+1); // 下一行首元素的首地址,即数组元素 4 的首地址

  4. printf("%d <== *brr+1\n",*brr+1); // 数组首元素的下一个元素,即数组元素 2 的首地址

  5. printf("%d <== *(brr+1)\n",*(brr+1)); // *(brr+1)相当于brr[1],即下一行首元素的首地址

  6. printf("%d <== *(brr+1)+2 \n",*(brr+1)+2); //*(brr+1)+2相当于brr[1]+2,即数组元素 6 的首地址

  7. printf("%d <== &brr[1][2]\n",&brr[1][2]); // 数组元素 6 的地址

  8. printf("%d <== *(*(brr+1)+2)\n",*(*(brr+1)+2)); // 数组元素 6

  9. printf("%d <== *(brr[1]+2)\n\n",*(brr[1]+2)); // 数组元素 6

  10.  
  11. printf("%d <== brr[1][0]\n",brr[1][0]); // 数组元素 4

  12. printf("%d <== brr[0][3]\n",brr[0][3]); // 数组元素 4

  13. printf("%d <== &brr[1][0]\n",&brr[1][0]); // 数组元素 4 的首地址

  14. printf("%d <== &brr[0][3]\n",&brr[0][3]); // 数组元素 4 的首地址

根据上述分析,brr+1代表下一行首元素的首地址,brr+1时y跨过n个整型数据的长度(n为列数)。

brr[1][0]与brr[0][3]的地址相同,说明二维数组在内存中是连续的、线性存储的

一维数组的类型为int * 型,而 二维数组的类型为 int(*)[ ] 类型

例如:brr[2][3]的类型为 int (*brr)[3] ,即 brr 为指向数组的指针,该数组含有3个int型数据的一维数组,3  相当于列数。

二维数组的打印

 
  1. void show(int (*brr)[3],int row,int col) //row 行 col 列

  2. {

  3. //先遍历行,再遍历列

  4. for(int i=0;i<row;i++)

  5. {

  6. for(int j=0;j<col;j++)

  7. {

  8. printf("%d ",brr[i][j]);

  9. }

  10. printf("\n");

  11. }

  12. }

上述打印方式,只能打印列数为3的二维数组

将上述打印方式进行改进:

根据二维数组在内存中的存储方式,将传入的数组由二维改为一维,则在打印时根据 i * col + j  将二维数组顺序输出

 
  1. //二维数组打印进阶版

  2. void show2(int *brr,int row,int col) //row 行 col 列

  3. {

  4. //先遍历行,再遍历列

  5. for(int i=0;i<row;i++)

  6. {

  7. for(int j=0;j<col;j++)

  8. {

  9. printf("%d ",brr[i*col+j]); //0 1 2 3 4 5

  10. }

  11. printf("\n");

  12. }

  13. }

二维数组行列转换

 
  1. #include<stdio.h>

  2. void Change(int (*brr)[3],int (*crr)[2],int row,int col)

  3. {

  4. for(int i=0;i<row;i++)

  5. {

  6. for(int j=0;j<col;j++)

  7. {

  8. crr[j][i] = brr[i][j];

  9. }

  10. }

  11. }

  12.  
  13. void show2(int *brr,int row,int col) // 打印数组元素

  14. {

  15. //先遍历行,再遍历列

  16. for(int i=0;i<row;i++)

  17. {

  18. for(int j=0;j<col;j++)

  19. {

  20. printf("%d ",brr[i*col+j]); //0 1 2 3 4 5

  21. }

  22. printf("\n");

  23. }

  24. }

  25. int main()

  26. {

  27. int brr[2][3]={1,2,3,4,5,6};

  28. int crr[3][2];

  29. Change(brr,crr,2,3);

  30. show2((int *)crr,3,2);

  31. }

下(上)三角矩阵

 
  1. #include<stdio.h>

  2. #define ROW 5

  3. void Fun(int (*brr)[ROW])

  4. {

  5. int count = 1;

  6. for(int i = 0;i < ROW;i++)

  7. {

  8. for(int j = 0;j < ROW;j++)

  9. {

  10. if(i >= j) //上三角矩阵此条件改为i <= j 即可

  11. {

  12. brr[i][j] = count++;

  13. }

  14. }

  15. }

  16. }

  17. void show(int *brr,int row,int col)

  18. {

  19. for(int i=0;i<row;i++)

  20. {

  21. for(int j=0;j<col;j++)

  22. {

  23. printf("%4d",brr[i*col+j]);

  24. }

  25. printf("\n");

  26. }

  27. }

  28. int main()

  29. {

  30. int brr[ROW][ROW] = {};

  31. Fun(brr);

  32. show((int *)brr,ROW,ROW);

  33. }

对称矩阵

 
  1. #include<stdio.h>

  2. #define ROW 5

  3. void Fun2(int (*brr)[ROW])

  4. {

  5. srand(time(0)); //随机种子

  6. for(int i = 0;i < ROW;i++)

  7. {

  8. for(int j = 0;j < ROW;j++)

  9. {

  10. if(j > i)

  11. {

  12. brr[i][j] = rand()%10; // 为了便于打印,只取随机数的个位数

  13. //[0-n) rand 函数返回该范围为 0 到 RAND_MAX (32767) 的一个伪随机整数

  14. }

  15. else if(i == j)

  16. {

  17. brr[i][j] = 0;

  18. }

  19. else

  20. {

  21. brr[i][j] = brr[j][i] ;

  22. }

  23. }

  24. }

  25. }

  26. void show(int *brr,int row,int col)

  27. {

  28. for(int i=0;i<row;i++)

  29. {

  30. for(int j=0;j<col;j++)

  31. {

  32. printf("%4d",brr[i*col+j]); //0 1 2 3 4 5

  33. }

  34. printf("\n");

  35. }

  36. }

  37. int main()

  38. {

  39. int brr[ROW][ROW] = {};

  40. Fun2(brr);

  41. show((int *)brr,ROW,ROW);

  42. }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值