数组是具有一定顺序关系的若干个变量的集合,组成数组的各个变量称为数组的元素 数组中各元素的数据类型要求相同,用数组名和下标确定。数组可以是一维的,也可以是多维的。
1.2 一维数组的定义一维数组是指只有一个下标的数组。它在计算机的内存中是连续存储的
说明形式为:<存储类型> <数据类型 > <数组名>[<表达式>]
例如:int a[6]; 数组名a表示内存首地址,sizeof(a)是数组占用的总内存空间, C语言数组编译时,不会对数组做越界检查,自己要注意。 a[6]表示a有6个元素,分别为a[0] a[1] a[2] a[3] a[4] a[5]1.3 一维数组的引用
C语言中规定数组必须逐个元素引用,而不能整体引用,比如下面这样是错误的,数组的引用实际上是数组元素的引用,数组元素需要用数组名[下标]表示:
int a[10];
printf("%dn",a);
如下演示是正确的,计算斐波那契数列前10项并逆序输出结果:
#include1.4 一维数组的初始化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 %dn",i , a[i]); return 0; }
我们定义的任何形式的变量尽量都初始化,防止后续遇到问题无法快速定位,因为一个变量如果没有初始化及赋值就直接拿来使用的话,这个值是随机的,因为局部变量来说我们是去栈上开辟了空间,但是栈上原来可能是有数据的,不初始化的话就会直接把栈上的数据拿过来。如下演示所示(没对a[10]初始化):
#includeint main(int argc, char const *argv[]) { int a[10]; for (int i = 0; i < 10; i++) { printf("a[%d] is %dn", 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};
二、一维数组的内存分配
在内存中,数组中的元素占用连续空间,并且根据单个元素所占存储空间来进行内存分配。
#includeint 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 : %pn", i, &a[i]); } for ( i = 0; i < 6; i++) { printf("b[%d] address is : %pn", 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]3.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五、字符数组 5.1 字符数组定义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("%pt",&a[i][j]); printf("%dn",a[i][j]); } } printf("%p %ld %ldrn",a,sizeof(a),sizeof(a[1][1])); return 0; }
字符数组是元素的数据类型为字符类型的数组 char c[10],ch[3][4],diamond[][5];
5.2 字符数组初始化①逐个字符元素赋值初始化
char ch[6] = {'a' , 'b' , 'c' , 'd' , 'e' , ' '};
②使用字符串常量为数组元素赋值
char ch[6] = {"abcde"}; //要给 留位置 会自动补
char ch[6] = "abcde";
char ch[] = "abcde";
char ch[5] = "abcde"; //会报错,因为字符串隐含' ',5个位置不够放
六、字符串的定义、输入输出
6.1 字符串定义
字符串指的是以’ ’作为结束字符的一组字符,在C语言中没有专门的字符串变量,通常用一个字符数组来存放一个字符串。
6.2 字符串输入输出使用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 :%sn", i, s); i++; } return 0; }
C库中,提供了很多字符串处理函数,利用好这些函数,能够让编程事半功倍。
7.1 字符串拷贝函数strcpy可以在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:%sn", 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:%sn", dest,src); return 0; }
注意:在使用strcat函数时,需要注意目标串应该要有足够的空间。(目标串’ ’被删除然后连接源串)
头文件:string.h 函数原型:int strcmp(const char *s1 , const char *s2) 功能:对两串从左向右逐个字符比较 参数:s1 s2为两个串的起始地址 返回值:int型整数 若s1 < s2,返回负整数 s1 > s2 ,返回正整数 s1 = s2 , 返回0
示例:
#include7.4 求字符串长度函数strlen#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 = s2n"); else if(t > 0) printf("s1 > s2n"); else printf("s1 < s2n"); return 0; }
头文件:string.h 函数原型:size_t strlen(const char *s) 功能:求字符串长度(不含' ') 参数:s为字符串 返回值:字符串长度(不含' ')
示例:
#include7.5 字符串按特定格式分割函数 strtok(常用)#include #define N 50 int main(int argc, char const *argv[]) { char s[N] = "welcome"; printf("s strlen = %ldn", strlen(s)); //字符串长度 printf("s sizeof = %ldn", sizeof(s)/sizeof(char)); //整个数组大小 return 0; }
头文件:string.h 函数原型:char *strtok(char *s , const char *delim) 功能:将字符串分割成一个个片断 参数:s为要分解的字符串 delim为分隔符字符串 返回值:分解出的字符串地址
当strtok在参数s的字符串中发现了delim中包含的分隔符时,会将该字符串改为’ ’字符。在第一次调用时,strtok必须给参数s字符串,往后的调用,则将s设置为NULL。每次调用成功则返回指向被分割出片段的指针。
示例程序如下:
#include7.6 其他常用字符串函数(可用man手册查看用法,自行测试,学习一个函数最后的方法就是验证它)#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("%sn", 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); //转换成小写八、总结练习 1、从终端输入10个数字(乱序),分别利用冒泡排序和简单选择排序法对这10个数字排序,结果从小到大排列。(温馨提示:冒泡排序和简单选择排序是两个不同的原理。)
答:
①冒泡排序:
思路:冒泡排序概念:它重复地走访过要排序的数列,一次比较两个元素,如果顺序错误就交换。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成
程序:
#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; }
演示情况:
②简单选择排序
思路:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
程序:
#include#define N 10 int main(int argc, char const *argv[]) { int a[N] = {0}; int i = 0 , j = 0 , r = 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++) { 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; } } printf("the array after sort:n"); for ( i = 0; i < N; i++) { printf("%5d",a[i]); } printf("n"); return 0; }
演示情况:
答:
#includeint 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 = %dn",max,row,column); return 0; }
结果演示:
代码如下:
#includeint 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("%dn",a[-1][1]); return 0; }
结果演示:
答:
#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:%sn",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] != ' ') { if (str[i] == ' ') { num++; } i++; } printf("the space num is: %dn", num); return 0; }
ps:欢迎大佬指正,共同学习进步。



