数组是具有一定顺序关系的若干个变量的集合,组成数组的各个变量称为数组的元素 数组中各元素的数据类型要求相同,用数组名和下标确定。数组可以是一维的,也可以是多维的。
一维数组是指只有一个下标的数组。它在计算机的内存中是连续存储的
说明形式为:<存储类型> <数据类型 > <数组名>[<表达式>]
例如:int a[6]; 数组名a表示内存首地址,sizeof(a)是数组占用的总内存空间,
C语言数组编译时,不会对数组做越界检查,自己要注意。
a[6]表示a有6个元素,分别为a[0] a[1] a[2] a[3] a[4] a[5]
C语言中规定数组必须逐个元素引用,而不能整体引用,比如下面这样是错误的,数组的引用实际上是数组元素的引用,数组元素需要用数组名[下标]
表示:
int a[10];
printf("%d\n",a);
如下演示是正确的,计算斐波那契数列前10项并逆序输出结果:
#include
int main(int argc, char const *argv[])
{
int i = 0 , a[10] = {0};
a[0] = a[1] = 1;
for(i = 2 ; i < 10 ; i++)
{
a[i] = a[i-2] + a[i-1];
}
printf("fibonacci numbers...\n");
for(i = 9 ; i > 0 ; i--)
printf("a[%d] is %d\n",i , a[i]);
return 0;
}
我们定义的任何形式的变量尽量都初始化,防止后续遇到问题无法快速定位,因为一个变量如果没有初始化及赋值就直接拿来使用的话,这个值是随机的,因为局部变量来说我们是去栈上开辟了空间,但是栈上原来可能是有数据的,不初始化的话就会直接把栈上的数据拿过来。如下演示所示(没对a[10]初始化):
#include
int main(int argc, char const *argv[])
{
int a[10];
for (int i = 0; i < 10; i++)
{
printf("a[%d] is %d\n", i , a[i]);
}
return 0;
}
数组初始化有七种情况:
1、局部变量不初始化:对于局部变量数组,若定义时未初始化,则数组元素值为随机值。
2、static数组不初始化:对于static修饰的数组,在内存上是存在全局与静态区,这里会进行清0处理(清bss段),因此元素都为0
3、全局数组不初始化:对于全局数组,在内存上是存在全局与静态区,这里会进行清0处理(清bss段),因此元素都为0
4、全部初始化:所有元素给一个初值
int a[5] = {1 , 2 , 3 , 4 , 5};
5、部分初始化:数组如果部分元素赋值,其他元素自动赋值0
int a[5] = {1 , 2}; //此时a[0] = 1 a[1] = 2 a[3] = 0 a[4] = 0
6、数组全部初始化为0(特殊写法)
int a[5] = {0};
在内存中,数组中的元素占用连续空间,并且根据单个元素所占存储空间来进行内存分配。
#include
int main(int argc, char const *argv[])
{
int i = 0;
char a[6] = {0};
int b[6] = {0};
for ( i = 0; i < 6; i++)
{
printf("a[%d] address is : %p\n", i, &a[i]);
}
for ( i = 0; i < 6; i++)
{
printf("b[%d] address is : %p\n", i, &b[i]);
}
return 0;
}
从上面可以看出,char型数组元素地址连续,且相差一个字节。int型数组元素地址连续且相差4字节。
二维数组是指有两个下标的数组。但是它在计算机的内存中是连续存储的,二维数组在内存上实际是一维的。
说明形式为:<存储类型> <数据类型 > <数组名>[<表达式1>][<表达式2>]
表达式1可省略 2不可省略
int a[2][3] //2代表行 3代表列
// a[0][0] a[0][1] a[0][2]
// a[1][0] a[1][1] a[1][2]
二维数组初始化与一维数组类似,主要是如下几种:
1、降维初始化
int a[2][3] = {{ 1 , 2 , 3 } , { 4 ,5 , 6 }}; //完全初始化
int a[2][3] = {{1} , {4}}; //部分初始化 第一行 1 0 0 第二行 4 0 0
2、按线性存储形式给二维数组赋值初始化
int a[2][3] = {1 , 2 , 3 , 4 , 5 , 6};
int a[2][3] = { 1 , 2}; //第一行 1 2 0 第二行 0 0 0
3、省略左边(行)下标范围方式初始化
int a[][3] = {1 , 2 , 3 , 4 , 5 , 6}; /第一行1 2 3 第二行 4 5 6
//不能写int a[2][]这种形式
由于内存是一维的,C语言中,二维数组采取了和一维数组类似的存储方式,按行优先存,存储第一行的元素后,再存第二行的。
a[0]代表&a[0][0] ,a[0]+2代表&a[0][2]
(注意:在数组a[2][3]中,a代表二维数组名,a[0]代表一维数组名,只要是数组名就是地址常量,不可以直接写a++ a[0]++)
有如下例子,有6元素的二维数组,在内存中的组织形式可用代码验证:
#include
int main(int argc, char *argv[])
{
int a[2][3] = {{1,6}};
int i = 0,j = 0;
for(i = 0; i < 2; i++)
{
for(j = 0; j < 3; j++)
{
printf("%p\t",&a[i][j]);
printf("%d\n",a[i][j]);
}
}
printf("%p %ld %ld\r\n",a,sizeof(a),sizeof(a[1][1]));
return 0;
}
字符数组是元素的数据类型为字符类型的数组 char c[10],ch[3][4],diamond[][5];
①逐个字符元素赋值初始化
char ch[6] = {'a' , 'b' , 'c' , 'd' , 'e' , '\0'};
②使用字符串常量为数组元素赋值
char ch[6] = {"abcde"}; //要给\0留位置 会自动补\0
char ch[6] = "abcde";
char ch[] = "abcde";
char ch[5] = "abcde"; //会报错,因为字符串隐含'\0',5个位置不够放
字符串指的是以’\0’作为结束字符的一组字符,在C语言中没有专门的字符串变量,通常用一个字符数组来存放一个字符串。
使用scanf和printf进行字符串输入输出,此时格式化符号使用’%s’,见下面的代码:
#include
#define N 20
int main(int argc, char const *argv[])
{
int i = 0;
char s[N] = {0};
printf(">");
while (scanf("%s", s) != EOF) //scanf会以空格作为结束标识符
{
printf(">");
printf("i = %d :%s\n", i, s);
i++;
}
return 0;
}
C库中,提供了很多字符串处理函数,利用好这些函数,能够让编程事半功倍。
可以在linux终端使用man 3 strcpy查看strcpy的详细用法(所有系统提供的都可以这样查)。
头文件:string.h
函数原型:char *strcpy(char *dest , const char *src)
功能:字符串拷贝
参数:src:源串起始地址 dest:目标串起始地址
返回值:目标串起始地址
示例:
#include
#include
#define N 50
int main(int argc, char const *argv[])
{
char dest[N];
char src[] = "welcome";
strcpy(dest, src);
printf("dest: %s src:%s\n", dest,src);
return 0;
}
头文件:string.h
函数原型:char *strcat(char *dest , const char *src)
功能:字符串连接,把字符串src连接到dest后面
参数:src:源串起始地址 dest:目标串起始地址
返回值:目标串起始地址
示例:
#include
#include
#define N 50
int main(int argc, char const *argv[])
{
char dest[N] = "welcome";
char src[] = "china";
strcat(dest, src);
printf("dest: %s src:%s\n", dest,src);
return 0;
}
注意:在使用strcat函数时,需要注意目标串应该要有足够的空间。(目标串’\0’被删除然后连接源串)
头文件:string.h
函数原型:int strcmp(const char *s1 , const char *s2)
功能:对两串从左向右逐个字符比较
参数:s1 s2为两个串的起始地址
返回值:int型整数 若s1 < s2,返回负整数 s1 > s2 ,返回正整数 s1 = s2 , 返回0
示例:
#include
#include
#define N 50
int main(int argc, char const *argv[])
{
int t = 0;
char s1[N] = {0};
char s2[N] = {0};
printf(">");
scanf("%s%s",s1,s2);
t = strcmp(s1,s2);
if (t == 0)
printf("s1 = s2\n");
else if(t > 0)
printf("s1 > s2\n");
else
printf("s1 < s2\n");
return 0;
}
头文件:string.h
函数原型:size_t strlen(const char *s)
功能:求字符串长度(不含'\0')
参数:s为字符串
返回值:字符串长度(不含'\0')
示例:
#include
#include
#define N 50
int main(int argc, char const *argv[])
{
char s[N] = "welcome";
printf("s strlen = %ld\n", strlen(s)); //字符串长度
printf("s sizeof = %ld\n", sizeof(s)/sizeof(char)); //整个数组大小
return 0;
}
头文件:string.h
函数原型:char *strtok(char *s , const char *delim)
功能:将字符串分割成一个个片断
参数:s为要分解的字符串 delim为分隔符字符串
返回值:分解出的字符串地址
当strtok在参数s的字符串中发现了delim中包含的分隔符时,会将该字符串改为’\0’字符。在第一次调用时,strtok必须给参数s字符串,往后的调用,则将s设置为NULL。每次调用成功则返回指向被分割出片段的指针。
示例程序如下:
#include
#include
int main()
{
char str[80] = "This is - www.baidu.com - website";
const char s[2] = "-";
char *token;
/* 获取第一个子字符串 */
token = strtok(str, s);
/* 继续获取其他的子字符串 */
while (token != NULL)
{
printf("%s\n", token);
token = strtok(NULL, s);
}
printf("\n");
for (int i = 0; i < 34;i++)
printf("%c", str[i]);
printf("\n");
return 0;
}
char *strncpy(char *dest, const char *src, size_t n); //复制src串指定长度n到目标dest串
char *strncat(char *dest, const char *src, size_t n);//附加指定长度字符串
int strcasecmp(const char *s1, const char *s2); //忽略大小写比较字符
int strncmp(const char *s1, const char *s2, size_t n); //比较两个串的前n个字符
char *strchr(const char *s, int c); //在字符串s中查找指定字符c
char *strstr(const char *haystack, const char *needle); //在字符串中查找字符串
int isalpha(int c); //检查是否为字母字符
int islower(int c); //检查是否为小写字母字符
int isupper(int c); //检查是否为大写字母字符
int isdigit(int c); //检查是否为数字
int toupper(int c); //转换成大写
int tolower(int c); //转换成小写
答:
①冒泡排序:
思路:冒泡排序概念:它重复地走访过要排序的数列,一次比较两个元素,如果顺序错误就交换。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成
程序:
#include
#define N 10
int main(int argc, char const *argv[])
{
int a[N] = {0};
int i = 0 , j = 0 , t = 0;
printf("please input %d numbers:\n",N);
for (i = 0; i < N; i++)
{
scanf("%d",&a[i]);
}
for (i = 0; i < N-1; i ++)
for (j = 0; j < N - 1 - i; j++)
{
if (a[j] > a[j+1])
{
t = a[j];
a[j] = a[j+1];
a[j+1] = t;
}
}
printf("the array after sort:\n");
for ( i = 0; i < N; i++)
{
printf("%5d",a[i]);
}
printf("\n");
return 0;
}
演示情况:
②简单选择排序
思路:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
程序:
/*
* @Description:
* @Author: 余红祥
* @Date: 2022-07-02 13:58:15
* @LastEditTime: 2022-07-02 14:02:27
* @LastEditors:
*/
#include
#define N 10
int main(int argc, char const *argv[])
{
int a[N] = {0};
int i = 0 , j = 0 , r = 0 , t = 0;
/*1、输入*/
printf("please input %d numbers:\n",N);
for (i = 0; i < N; i++)
{
scanf("%d",&a[i]);
}
/*2、排序过程*/
for ( i = 0; i < N - 1; i++)
{
r = i;
for (j = i + 1; j < N; j++)
{
if (a[j] < a[r])
r = j;
}
if (r != i)
{
t = a[r];
a[r] = a[i];
a[i] = t;
}
}
/*3、显示*/
printf("the array after sort:\n");
for ( i = 0; i < N; i++)
{
printf("%5d",a[i]);
}
printf("\n");
return 0;
}
答:
#include
int main(int argc, char const *argv[])
{
int a[3][4] = {{1 , 65 , 34 , 67} , {23 , 33 , 57 , 24} , { 1 , 2 ,3 ,4} };
int max = 0 , i = 0 , j = 0;
int row = 0 , column = 0;
max = a[0][0]; //假定第一个元素为最大值 用后面的和第一个比
for ( i = 0; i < 3; i++)
{
for ( j = 0; j < 4; j++)
{
if ( a[i][j] > max )
{
max = a[i][j];
row = i;
column = j;
}
}
}
printf("max value is : %d , row = %d , column = %d\n",max,row,column);
return 0;
}
代码如下:
#include
int main(int argc, char *argv[])
{
static int a[10][10];
int i = 0,j = 0;
for(i = 0; i < 10; i++)
{
a[i][0] = 1;
for(j = 1; j <= i; j++)
{
a[i][j] = a[i-1][j-1]+a[i-1][j];
}
}
for(i = 0;i<10;i++)
{
for(j = 0;j<=i;j++)
printf("%d ",a[i][j]);
printf("\n");
}
//printf("%d\n",a[-1][1]);
return 0;
}
答:
/*
* @Description:
* @Author: 余红祥
* @Date: 2022-07-02 16:23:56
* @LastEditTime: 2022-07-02 16:28:19
* @LastEditors:
*/
#include
#include
#define N 100
int main(int argc, char **argv)
{
char str[N] = {0};
printf("please input a string:\n");
scanf("%s",str) ;
int length = strlen(str);
int i = 0, j = 0 , pos = 0;
for(i = 0;i < length;i++){
for(j = i+1;j < length;j++)
{
if(str[i] == str[j]) //有相同字符
{
for(pos = j;pos < length; pos++)
{
str[pos] = str[pos+1]; //下一个字符赋值给当前字符 (相当于删除字符操作)
}
length--;
j--; //由于当前字符已删除,需要再次判断当前位置的字符是否和第i个字符相等
}
}
}
printf("new string:%s\n",str);
return 0;
}
答:
#include
#include
#define N 100
int main(int argc, char const *argv[])
{
int i = 0 , num = 0;
char str[N] = {0};
printf("please input a string:\n");
gets(str); //本来这里用的是scanf 但是scanf遇到空格认为是结束符了 改用gets
while (str[i] != '\0')
{
if (str[i] == ' ')
{
num++;
}
i++;
}
printf("the space num is: %d\n", num);
return 0;
}