嵌入式学习 2022.1.25 C语言基础与提高3
一、数组、指针的定义和使用
1、数组类型的应用场合


2、定义、初始化和引用
2.1一维数组的定义

2.2一维数组的初始化
当数组被说明为静态(static)存储类型或外部存储类型(即在所有函数外部定义)时,则在不显式给出初值的情况下,数组元素将在程序编译阶段自动初始化为0。
static int a[4]
等价于
static int a[4]={0,0,0,0}
2.3一维数组的引用

3、一维数组应用举例
3.1冒泡法排序

#include <stdio.h>
main( )
{ int i, j, t, a[11];
printf("input 10 numbers: \n");
for (i=1; i<=10; i++)
scanf(“%d”, &a[i]); //输入循环
printf("\n");
for (i=1; i<=9; i++) //冒泡排序
for (j=10; j>=i+1; j--)
if (a[j]<a[j-1])
{
t=a[j];
a[j]=a[j-1];
a[j-1]=t;
} //注:可以使用a[0]
for (i=1; i<=10; i++) //输出显示
printf(“%d\n”, a[i]);
}
3.2Fibonacci级数
用数组来处理求Fibonacci的前20项。 例如:1,1,2,3,5,8,13,21,34,65,……
#include <stdio.h>
main( )
{ int i;
static int f[20]={1, 1};
for (i=2; i<20; ++i) f[i]=f[i-1]+f[i-2];
for (i=0; i<20; ++i)
{if (i%5==0) printf("\n");
printf("%12d", f[i]);
}
}
3.3折半查找
#include <stdio.h>
main( )
{int up=9, low=0, mid, found=0, find;
int a[10]={1, 5, 6, 9, 11, 17, 25, 34, 38, 41};
scanf(〞%d 〞, &find);
printf(〞\n 〞);
while (up>=low && !fount)
{mid=(up+low)/2;
if(a[mid]==find)
{found=1; break;}
else if(a[mid]>find)
up=mid-1;
else low=mid+1;
}
if(found) printf(〞found number is %dth 〞mid);
else printf(〞no found 〞);
}
4、一维数组名作函数参数
使用简单变量作函数参数,能由实参向形参传递一个数据。使用数组名作函数参数,属于“地址调用”能由主调函数向被调函数传递数组的首地址,并能由被调函数向主调函数传递多个数据。


若在被调函数中改变形参数组的元素值, 则实参数组中的元素值也会随之发生改变。
注意这种改变不是形参传给实参造成的(C 语言不允许这种反向的值传递),而是由于形参和实参两个数组在内存中因指向同一地址而共享同一段内存造成的。
5、二维数组及二维数组作函数参数应用举例
5.1二维数组的定义

按行存储:

5.2二维数组的初始化
如果对全部元素赋初值(即提供全部初始数据),则定义数据时对第一维长度可以不指定,但第二维长度不能省。
int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
等价于
int a[ ][4]={1,2,3,4,5,6,7,8,9,10,11,12};
5.3二维数组的引用

5.4二维数组作函数参数
(1)转置矩阵(练习)
输入NM的矩阵,输出它的转置矩阵。
Input
第一行为整数N,M(1≤N,M≤100)。
接着是一个NM的矩阵。
Output
转置矩阵。
Example Input
2 3
1 2 3
4 5 6
Example Output
1 4
2 5
3 6
#include<stdio.h>
int main(){
int n,m,i,j;
printf("Example Input\n");
scanf("%d %d",&n,&m);
int num[n][m];
int num1[m][n];
for(i=0;i<n;i++){
for(j=0;j<m;j++){
scanf("%d",&num[i][j]); //输入
}
}
for(i=0;i<m;i++){
for(j=0;j<n;j++){
num1[i][j]=num[j][i]; //转换
}
}
printf("Example Output\n");
for(i=0;i<m;i++){
for(j=0;j<n;j++){
printf("%d ",num1[i][j]); //输出
}
printf("\n");
}
return 0;
}
(2) *杨辉三角形(练习)
①一维数组实现
#include <stdio.h>
int main ()
{
int a[11], i, j, k, n, ij, m;
scanf("%d",&n);
printf("%8d\n%8d%8d\n",1,1,1);
for (i=2; i<=n; i++)
{
for (j=0; j<=i; j++)
{
ij=1;
m=1;
for(k=1; k<=i-j; k++)
ij=ij*k;
for(k=j+1; k<=i; k++)
m=m*k;
a[j]=m/ij;
}
for(k=0; k<=i; k++)
printf("%8d",a[k]);
printf("\n");
}
}
②二维数组实现
#include <stdio.h>
main ()
{
int a[11][11], i, j, n;
a[1][1]=1;
a[2][1]=1;
a[2][2]=1;
scanf("%d",&n);
for (i=3; i<=n; i++)
{
a[i][1]=1;
for (j=2; j<=i-1; j++)
a[i][j]=a[i-1][j-1]+a[i-1][j];
a[i][i]=1;}
for(i=1; i<=n; i++)
{
for(j=1; j<=i; j++)
printf("%8d", a[i][j]);
printf("\n");
}
}
}
6、字符数组
6.1字符数组的定义:

6.2字符数组的初始化
如初值个数等于数组长度,在定义时可以省略数组长度,系统会自动根据初值个数确定数组长度。

由于字符串在内存中存储时,后边自动 加'\0',字符数组初始化可为:
char c[ ]={"I am happy"};
也可为
char c[ ]="I am happy";
用二维字符数组可存放多个字符串,第二维的长度表示字符串的长度,不能省略,应按最长的字符串长度设定;
第一维的长度代表要存储的字符串的个数,可以省略。
6.3字符数组的引用

6.4字符串和字符串结束标志
6.5字符函数与字符串的关系
- 1.字符串是采用字符数组来表示的,只是在有效字符串后自动加字符串结束标志'\0'。
- 2.字符数组不是字符串,只有当字符型一维数组中的最后一个元素值为’\0’时,它才构成字符串。
- 3.对于一个字符串常量,那么这个字符串常量本身代表的就是该字符串在内存中所占连续存储单元的首地址,是一个地址常量 。
- 4.如果将字符串赋值给了一个一维数组,那么这个一维数组的名字就代表这个首地址。
6.6字符数组的输入输出
- 利用循环,逐个字符输入输出。👉用格式赋%c输入或输出一个字符。
- 将整个字符串一次输入或输出。👉用格式赋%s输入或输出一个字符串。
(1)字符串输入

(2)字符串输出

6.7字符串处理函数——#include <string.h>
(1)puts函数

(2)gets函数

用puts和gets函数只能输入或输出一 个字符串,而不能写成:
puts(c1,c2,c3);
gets(c1,c2,c3);
(3)strcat函数

(4)strcpy函数

(5)strcmp函数

(6)strlen函数

(7)strlwr函数

(8)strupr函数

二、指针和数组的联系
1、指针的概念
(1) 什么是变量的地址? 什么是变量的内容?

(2) 什么是直接寻址? 什么是间接寻址?
直接按变量名来存取变量内容的访问方式, 称为直接寻址。
本质:变量是通过变量地址来访问变量内容的。

通过指针变量来间接存取它所指向的变量的访问方 式,称为间接寻址。
专门用于存放地址型数据的变量i_pointer就是指针变量。(放钥匙的抽屉)

指针是变量的地址;
变量的地址就是变量的指针;
(3) 取地址运算符& 与 间接访问运算符 *


2、为什么引入指针的概念
- 指针提供通过变量地址访问变量的手段。
- 指针为C的动态内存分配系统提供支持 。
- 指针为动态数据结构(例如链表、队列、二叉树等)提供支持,操作系统的编写 。
- 指针可以改善某些子程序的效率。
3、指针变量
(1)变量指针与指针变量
(2)定义

(3)引用
①⒈一般变量只能存放数据,而不能存放 变量的地址;指针变量只能存放变量 的指针,即变量首地址,必须用相同 基类型的变量的地址对其进行赋值。
int n, *p;
p=n; ×
p=&n; √
②与指针变量有关的两个特殊运算符:
* :间接访问运算符。
&:取地址运算符。
int n, *p;
p=&n; 此时*p和n表示的是同一变量。
③指针变量必须经初始化后才能使用, 否则指针变量所指向的存储单元是不 确定的,对其所作的赋值等操作将是 很危险的。
④由于指针的值就是地址,因此,指针 运算实质上就是对地址的运算。因此, 指针运算只能参与赋值运算、算术运算 和关系运算。其中,指针可参与的算术运算只有两种:加和减,即加、减一个整数或自增、自减运算。 ++p表示指向 下一个变量。--p指向上一个变量。
⑤运算符*和++、--优先级等同,连续运算,采用右结合。
下列各语句的含义如下:
a=*p++ 先运算p++,但为后增运算,因而先将*p的值赋给a,然后p加1。
a=(*p)++ 先取*p的值,赋给a。然后将p所指向的变量内容加1。

浙公网安备 33010602011771号