5_数组 & 字符串
数组
数组属于构造数据类型。
数组元素,可以是基本数据类型,也可以是构造类型;
空格 \t
换行 \n
———————————————————————————————————————————————
数组的大小
int score[10];
sizeof(score); // 40,一个int为4B,10个占用40B
sizeof(int); // 4
int length = sizeof(score)/sizeof(int); // 可以通过这种方式计算出数组长度
// 注意:即使数组越界,sizeof依然会返回一个正确的数组元素占用的大小值
// 例如,score[10000],下标越界,但是sizeof依然可以返回4
int len = sizeof(score)/sizeof(score[10000]);
———————————————————————————————————————————————
数组初始化
int a[10] = {1,2,3,4,5,6,7,8,9,0};
int b[10] = {1,2,3}; // 前3个赋值,后7个全部为默认0;
int a[10] = {0}; // 10个元素全部赋值为0
int a[] = {1,2,3,4,5};; // 未指定数组长度,只指定成员
int a[10] = {1}; // 第0个为1,其余9个全部为0
———————————————————————————————————————————————
数组的内存结构
score // 是一个地址,也可以视作是一个指针
score[0] // 是一个值,数组元素的值
&score[0] // 是一个地址,内存地址
printf("%X\n",&score[0]);
大端方式,内存地址存放数据0000 0063 → 和正常的思维方式相同
小端方式,内存地址存放数据6300 0000 → 和正常思维方式相反
一般内存默认按字节编址,一个字节8位,也就是十六进制的两位,
也就是说,一个内存地址里面可以放8位的数据。
// 例1、输入10个值存到数组,找到其中的最大值;
// 例2、数组逆置
#include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
for(int i=0;i<10;i++>)
{
printf("%d\n",arr[i]);
}
int i = 0;
int j = sizeof(arr)/sizeof(arr[0]);
while(i<j>)
{
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
i++;
j--;
}
}
// 例3、冒泡排序
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int arr[10] = {7,4,5,75,345,26,457,623,645,856};
int len = sizeof(arr) / sizeof(arr[0]) - 1;
for(int i = 0;i<=len;i++>)
{
for(int j = 0;j<len-i;j++>)
{
if(arr[j]>arr[j+1])
{
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1 = temp;]
}
}
}
}
———————————————————————————————————————————————
二维数组
- 按行优先存储 → 默认情况下
- 按列优先存储
二维数组内存模型
arr
arr[0] // arr和arr[0]、&arr[0][0]指向的是同一个地址
&arr[0][0]
arr[1] // arr[1]和arr[0]相差了一个行元素个数*类型大小的地址单元
&arr[0][1]
二维数组初始化
int a[3][4] = {
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,16}
}
int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12}; // 连续赋值
int a[3][4] = {1,2,3,4}; // 部分赋值
int a[3][4] = {0}; //二维数组全部赋值为0
int a[][4] = {1,2,3,4,5,6,7,8}; // []中不定义元素个数,定义的时候必须要初始化赋值;
int a[4][]; // 这种初始化方式会报错
例、10名学生、三门成绩,求出每名学生的总成绩、平均成绩、各科平均成绩;
例、二维数组排序
———————————————————————————————————————————————
多维数组
int a[3][4][5] = {
{
{1,2,3,4},
{5,6,7,8,9},
{0},
{0}
},
{ {0},{0},{0},{0} },
{ {0},{0},{0},{0} }
};
———————————————————————————————————————————————
字符数组
注意:C语言没有字符串,字符串要用字符数组来表示;
char arr[10];
char arr[10] = {'H','E','L','L','O'};
/**
* 字符串数组的接收有两种
* %s → 会接收char结束标志之前的字符;
* %c → 会接收字符数组里全部字符,\0也会打印出来;
*/
char c[] = {'a','','b','c'};
printf("%s\n",c); // 打印a
printf("%c\n",c); // 打印a bc 中间空的为空字符
char arr[1000] = {"hello"};
char arr[10] = "hello"; // 这是一个字符串,实际占用了6个字符位置,有一个结尾的标志符\n
char arr[10] = {'h','e','l','l','o'}; // 占用5个字符位置,没有结束标志
printf("%s\n",arr); // 因为arr没有结束标志,所以会打印arr的全部10个元素的值,在hello的后面是一堆乱码
// Tips: 空格可以作为scanf的结束标志
scanf("%s",arr); // 输入hello world
printf("%s\n",arr); //会打印hello,空格会被认为是\0
scanf("%[^\n]",arr); // 此时输入的值里面就可以带空格,hello world
printf("%s\n",arr); // 此时打印的是hello world
———————————————————————————————————————————————
字符串追加
#include <stdio.h>
int main(){
char str[] = "abcdef";
char str2[] = "123456";
char dst[100]; // 此时也可以char dst[100] = {0},这样就可以不用自己加字符串结束符了
int i = 0;
while(str[i] != 0)
{
dst[i] = str[i];
i++;
}
int j = 0;
while(str2[j] != 0)
{
dst[i+j] = str2[j];
j++;
}
dst[i+j] = 0; // 手动加上字符串结束符
printf("%s\n",dst);
return 0;
}
———————————————————————————————————————————————
函数 - 产生随机数
#include <time.h>
time_t time(time_t *t);
#include <stdlib.h>
void srand(unsigned int seed);
int rand(void);
srand((unsigned int)time(NULL)); // 添加随机数种子
rand(); // 返回一个0-10000的随机数
// 例、双色球
srand((unsigned int)time(NULL));
rand()%33 + 1; // 生成1-33的随机数
for(int i = 0;i<6;i++)
{
ball[i] = rand()%33 + 1;
for(int j = 0;j<i;j++)
{
if(ball[i] == ball[j])
{
i--;
continue;
}
}
}
// Tips: 有\0就是字符串,没有就只是字符串数组
———————————————————————————————————————————————
字符串处理函数
- (1)、gets() 输入字符串,存入某一个变量中
char ch[100];
gets(ch); // 类似scanf,要求用户输入内容
printf("%s\n",ch);
———————————————————————————————————————————————
- (2)、puts()
puts(ch); // 输出一个字符串,自带换行
Tips:若ch[100],而gets中输入的字符内容多于100,puts会报错;
Tips:puts可以输入空格;
Tips:返回值,gets(ch)返回字符串的值,puts(ch)返回一个非负数(成功)或-1(失败);
int value = puts(ch); // 返回了一个数
char * p = gets(ch); // 返回了一个字符串,和ch的字符串一致
———————————————————————————————————————————————
- (3)、fgets() 用于文本操作,从流中读入固定大小的字符串,比scanf更安全;
/**
* fgets(字符指针,大小,输入流)
* 三个参数:字符指针,大小,文件流
* 将流中的内容读入到某一个变量当中
*/
char arr[100];
fgets(arr,100,stdin); // fgets输入空格也会当做字符串
puts(arr); // puts输出一个字符串,会自带一个换行符
Tips:若输入的大小小于原始指针对应区域的大小,会在字符串输入完成后自动加上\0;
例如,arr[10],输入hello world,
结果:输出hello wor,仅有9个字符,第10个字符\0不显示,同时,回车符也不会记录在内;
若arr足够长,则输出:hello world\n,带有一个换行符
如果输出采用puts,则输出:hello world\n\n,puts会自带一个\n
fgets,成功时,返回成功读取的字符串,失败时返回NULL
———————————————————————————————————————————————
- (4)fputs(字符指针,流) 将字符串写入流到指定的文件中
char arr[10] = "he\0llo";
fputs(arr,stdout);
// 结果输出he,fputs的输出到\0结束。
// 指定了格式的scanf,必须要输入a=1b=2c=3这种形式才能够成功给abc赋值
scanf("a=%db=%dc=%d",&a,&b,&c);
printf("%d %d %d",a,b,c);
scanf("%[^\n]",arr);
scanf("%d %d %d",&a,&b,&c);
scanf("%4d%4d%4d",&a,&b,&c); // %4d指四位字符,限定宽度的格式化
scanf("%1s%2s",arr1,arr2);
printf("%d\n",arr1);
printf("%d\n",arr2);
scanf("%*s%d",&arr); // 屏蔽某一类字符
scanf("%*d",&arr);
// %*d屏蔽数字,%*c屏蔽字符
scanf("%*[123456]%c",&ch); // %*[123456]表示屏蔽123456
printf("%c\n",ch);
// 例如在这里输入1h,会打印h,数字都会被过滤掉
printf("%.2f",3.1415);
printf("%5d",12); // 输出5个字符,输出:___12(右对齐,3个空格)
printf("%05d",12); // 输出00012
printf("%4s","abcdef"); // abcd
printf("%4s","ab"); // __ab
printf("%-4d",12); // 12__
Tips:要使用字符串的方法,<string.h>要引入;
———————————————————————————————————————————————
- (5)strlen()
char str[] = "abcdefg";
int len = strlen(str); // 计算的是字符串的有效长度,不包括\0
sizeof(arr); // 计算的是整个字符串占用空间的大小,包括\0
strlen("ab\n\0110"); // 返回多少?
注意,strlen的返回的字符串长度,以\0作为边界。
而sizeof则计算的是 字符串+\0 的长度;
如果 arr = {'h','e','l','l','o'},那么strlen(arr)就会是一个不确定的值,因为\0没有,即该字符没有边界;
———————————————————————————————————————————————
- (6)strcpy()
char *strcpy(char *dest,char*src)
将src里的字符串复制到dest中。从后面 → 前面
成功 → 返回dest的首地址
失败 → 返回NULL
注意:\0也会被复制
———————————————————————————————————————————————
- (7)strncpy()
char *strncpy(char *dest,const char *src,size_t n)
src是拷贝的来源,const说明src不能被更改。
char arr1[] = "hello world";
char arr2[100];
strncpy(arr2,arr1,5); // 此时printf(arr2)会返回一个乱码
// 这是一种有限拷贝,不会将\0拷贝到字符串
———————————————————————————————————————————————
- (8)strcat()
char *strcat(char *dest,const char *src);
将src追加到dest中,
但是注意,dest需要保证够大,能够放下所有的src;
———————————————————————————————————————————————
- (9)strncat()
char *strncat(char *dest,const char *src,size_t n);
有限拷贝,将src的前n个字符追加到dest中;
注意,追加后,dest会自带\0;
strncat(arr1,arr2,3);
———————————————————————————————————————————————
- (10)strcmp()
strcmp会比较两个字符的ASCII码的大小,
- 相等返回0
- 大于返回>0
- 小于返回<0
注意,
strcmp在不同的OS中返回值是不一样的,可能是ASCII的差值;
strcmp比较的是\0之前的有效字符
———————————————————————————————————————————————
- (11)strncmp()
int strncmp (s1,s2,size_t n);
比较两个字符的前n个字符,相等返回0,大于返回>0,小于返回<0;
同样的,比较的是\0之前的有效字符;
———————————————————————————————————————————————
- (12)sprintf()
sprintf(result,"a=%d,src=%s",a,src);
执行后,result被赋值,格式为a=%d,src=%s,里面的值为a和src;
返回值为实际格式化的字符个数,失败时返回-1;
———————————————————————————————————————————————
- (13)sscanf()
int sscanf(const char *str,const char *format),...)
从str中,按照format的格式,提取数值到多个变量当中。
char src[] = "a=10,b=20";
int a,b;
sscanf(src, "a=%d,b=%d", a, b);
// 结果是:a被赋值了10,b被赋值了20;
———————————————————————————————————————————————
- (14)strchr() → 查找某个字符出现的位置
char * strchr(const char*s, intc)
s → 字符串首地址
c → 匹配的字符
返回第一次出现的c字符的地址,失败时返回NULL;
arr = "hello";
strchr(arr,108); // ASCII码的108是'l'
———————————————————————————————————————————————
- (15)strstr() → 从字符串中查找另外一个字符串的位置
注意:汉字的查找只能用这个方法查,strchr不能用作汉字的查找;
返回字符串出现第一次的首地址,失败时返回NULL;
Tips;单个汉字占2字节,但是,strchr(arr,'哈'),等效于"哈",会返回乱码;
"哈哈" 这个字符串,占5个位置;
char src[] = "aabbccddeeff";
char *p = strstr(src,"cc"); // p里面就可以得到cc在src里面的首地址
———————————————————————————————————————————————
- (16)strtok()
char *strtok(char *str,const char *delim);
分割字符串,同时,会破坏原有的字符串结构;
返回分割后的首地址;
char a[100] = "abc*fvcv*ebcy*";
char *s = strtok(a,"*");
// strtok在这里会作用到第一个*,此时调用了一次后,返回的是abc
———————————————————————————————————————————————
- (17)atoi()
int atoi(const char *nptr)
将字符串转换成整数,忽略前面的空格;
以数字、正负号为起始;
atol 将字符串化为long类型
atof 将字符串化为float类型
返回值为指定的数据类型的数据
arr = " hello 100";
atoi(arr); // 结果是0
arr = " 100hello";
atoi(arr); // 结果100
———————————————————————————————————————————————
来源:oschina
链接:https://my.oschina.net/LinearLawX/blog/3182827