C总结-part_2-数组&字符串

C总结-part_2-数组&字符串

空格 	
换行 

———————————————————————————————————————————————

数组的大小

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
",&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
",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 → 会接收字符数组里全部字符,也会打印出来;
 */
char c[] = {"a","","b","c"};
printf("%s
",c); // 打印a
printf("%c
",c); // 打印a bc 中间空的为空字符

char arr[1000] = {"hello"};
char arr[10] = "hello"; // 这是一个字符串,实际占用了6个字符位置,有一个结尾的标志符


char arr[10] = {"h","e","l","l","o"}; // 占用5个字符位置,没有结束标志
printf("%s
",arr); // 因为arr没有结束标志,所以会打印arr的全部10个元素的值,在hello的后面是一堆乱码
// Tips: 空格可以作为scanf的结束标志
scanf("%s",arr); // 输入hello world
printf("%s
",arr);  //会打印hello,空格会被认为是

scanf("%[^
]",arr);  // 此时输入的值里面就可以带空格,hello world
printf("%s
",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
",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: 有就是字符串,没有就只是字符串数组

———————————————————————————————————————————————

字符串处理函数

  • (1)、gets() 输入字符串,存入某一个变量中
char ch[100];
gets(ch);       //  类似scanf,要求用户输入内容
printf("%s
",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:若输入的大小小于原始指针对应区域的大小,会在字符串输入完成后自动加上;

例如,arr[10],输入hello world,

结果:输出hello wor,仅有9个字符,第10个字符不显示,同时,回车符也不会记录在内;
若arr足够长,则输出:hello world ,带有一个换行符
如果输出采用puts,则输出:hello world ,puts会自带一个

fgets,成功时,返回成功读取的字符串,失败时返回NULL

———————————————————————————————————————————————

  • (4)fputs(字符指针,流) 将字符串写入流到指定的文件中
char arr[10] = "hello";
fputs(arr,stdout);
// 结果输出he,fputs的输出到结束。
// 指定了格式的scanf,必须要输入a=1b=2c=3这种形式才能够成功给abc赋值
scanf("a=%db=%dc=%d",&a,&b,&c);   
printf("%d %d %d",a,b,c);
scanf("%[^
]",arr);

scanf("%d %d %d",&a,&b,&c);

scanf("%4d%4d%4d",&a,&b,&c); // %4d指四位字符,限定宽度的格式化
scanf("%1s%2s",arr1,arr2);
printf("%d
",arr1);
printf("%d
",arr2);

scanf("%*s%d",&arr); // 屏蔽某一类字符
scanf("%*d",&arr);

// %*d屏蔽数字,%*c屏蔽字符
scanf("%*[123456]%c",&ch); // %*[123456]表示屏蔽123456
printf("%c
",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);  // 计算的是字符串的有效长度,不包括
        sizeof(arr);    // 计算的是整个字符串占用空间的大小,包括

strlen("ab
110");    // 返回多少?

注意,strlen的返回的字符串长度,以作为边界
而sizeof则计算的是 字符串+ 的长度;

如果 arr = {"h","e","l","l","o"},那么strlen(arr)就会是一个不确定的值,因为没有,即该字符没有边界;

———————————————————————————————————————————————

  • (6)strcpy()
char *strcpy(char *dest,char*src)
将src里的字符串复制到dest中。从后面 → 前面
成功 → 返回dest的首地址
失败 → 返回NULL

注意:也会被复制

———————————————————————————————————————————————

  • (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)会返回一个乱码
// 这是一种有限拷贝,不会将拷贝到字符串

———————————————————————————————————————————————

  • (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会自带;

strncat(arr1,arr2,3);

———————————————————————————————————————————————

  • (10)strcmp()

strcmp会比较两个字符的ASCII码的大小,

  • 相等返回0
  • 大于返回>0
  • 小于返回<0

注意,
strcmp在不同的OS中返回值是不一样的,可能是ASCII的差值;
strcmp比较的是之前的有效字符
———————————————————————————————————————————————

  • (11)strncmp()
int strncmp (s1,s2,size_t n);
比较两个字符的前n个字符,相等返回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

———————————————————————————————————————————————