C++笔记day5-二维数组、字符串、函数

172 阅读5分钟

二维数组:

int arr[10] = {1,2,3,5,6,7};

{1,2,3,5,6,7};
{1,2,3,5,6,7};
{1,2,3,5,6,7};
{1,2,3,5,6,7};

定义语法:

int arr[2][3] = 
	{
	{2, 5, 8},
	{7, 9 10}
	};

int arr[3][5] = {{2, 3, 54, 56, 7 }, {2, 67, 4, 35, 9}, {1, 4, 16, 3, 78}};

打印:
	for(i = 0; i < 3; i++)		// 行
	{
		for(j = 0; j <5; j++)   // 列
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}		

大小:

数组大小: sizeof(arr);

一行大小: sizeof(arr[0]): 二维数组的一行,就是一个一维数组。

一个元素大小:sizeof(arr[0][0])		单位:字节

行数:row = sizeof(arr)/ sizeof(arr[0])

列数:col = sizeof(arr[0])/ sizeof(arr[0][0])

地址合一:

printf("%p\n", arr); == printf("%p\n", &arr[0][0]); == printf("%p\n", arr[0]);

数组的首地址 == 数组的首元素地址 == 数组的首行地址。

二维数组的初始化:

1)常规初始化:

	int arr[3][5] = {{2, 3, 54, 56, 7 }, {2, 67, 4, 35, 9}, {1, 4, 16, 3, 78}};

2) 不完全初始化:

	int arr[3][5] = {{2, 3}, {2, 67, 4, }, {1, 4, 16, 78}};  
        未被初始化的数值为 0 

	int arr[3][5] = {0};	
        初始化一个 初值全为0的二维数组

	int arr[3][5] = {2, 3, 2, 67, 4, 1, 4, 16, 78};   
        【少见】 系统自动分配行列。

3)不完全指定行列初始化:

	int arr[][] = {1, 3, 4, 6, 7};  
        错误!二维数组定义必须指定列值。

  	int arr[][2] = { 1, 3, 4, 6, 7 };  
        可以不指定行值。

示例

#include <stdio.h>

int main(void)
{
	
		int arr[4][3] = { 
								{1,3,4},
								{3,4,5},
								{4,6,4},
								{2,3,3} };
		int row = sizeof(arr) / sizeof(arr[0]);
		int col = sizeof(arr[0]) / sizeof(arr[0][0]);
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
	printf("数组大小为:%u\n", sizeof(arr));
	printf("数组行的大小为:%u\n", sizeof(arr[0]));
	printf("数组一个元素的大小为:%u\n", sizeof(arr[0][0]));
	printf("数组行数为:%u\n", sizeof(arr) / sizeof(arr[0]));
	printf("数组列数为:%u\n", sizeof(arr[0]) / sizeof(arr[0][0]));

	printf("arr = %p\n", arr); //%p代表地址;
	printf("&arr[0] = %p\n", arr[0]); //本身相当于一个一维数组,不用加取地址符;
	printf("&arr[0][0] = %p\n", &arr[0][0]);

}

练习:求出5名学生3门功课的总成绩。

示例:一个学生的总成绩。一门功课的总成绩

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void)
{
	int scores[5][3];

	int row = sizeof(scores) / sizeof(scores[0]);
	int col = sizeof(scores[0]) / sizeof(scores[0][0]);
	
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			scanf("%d", &scores[i][j]);
		}
	}
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			printf("%d ", scores[i][j]);
		}
		printf("\n");
	}
	// 求一个学生的总成绩
	for (int i = 0; i < row; i++) //每个学生;
	{
		int sum = 0;
		for (int j = 0; j < col; j++) //每个学生的成绩;
		{
			sum += scores[i][j];
		}
		printf("第%d个学生的总成绩为%d\n",i+1,sum);
	}
	//求一门功课的总成绩
	for (int j = 0; j < col; j++)
	{
		int sum_1 = 0;
		for (int i = 0; i < row;i++)
		{
			sum_1 += scores[i][j];
		}
		printf("第%d门功课的总成绩为%d\n", j+1, sum_1);
	}
}

快捷导入代码:

VS --》 工具--》 代码片段管理器 --》 Visual C++

多维数组:【了解】

三维数组:[层][行][列]

数组类型 数组名[层][行][列];

int arr[3][3][4];

{ {12, 3, 4, 5}
  {12, 3, 4, 5} },

{ {12, 3, 4, 5}
  {12, 3, 4, 5} },

{ {12, 3, 4, 5}
  {12, 3, 4, 5} },

for(i = 0; i < 3; i++)  层

	for (j = 0; j < 3; j++)  行

		for (k = 0; k<4; k++)  列

			printf("%d ", arr[i][j][k]);

4维、5维、6维。。。N维。

示例

int main(void)
{
	int a[3][4][2] = {     //3层4行2列;
		{
			{2, 3},
			{5,6},
			{6,7},
			{9,1}
		},
		{
			{4, 3},
			{3,3},
			{6,8},
			{9,8}
		},
		{
			{1, 3},
			{3,4},
			{5,7},
			{4,2}
		}
	};
	for (int i = 0; i<3;i++)
	{
		for (int j = 0; j < 4; j++)
		{
			for (int k = 0; k < 2; k++)
			{
				printf("%d ", a[i][j][k]);
			}
			printf("\n");
		}
		printf("\n");
	}

	system("pause");
	return EXIT_SUCCESS;
}

int arr[10];

short arr[20];

long long arr[20];

字符数组 和 字符串区别:

字符数组: 
	char str[5] = {'h', 'e', 'l', 'l', 'o'};	

字符串:
	char str[6] = {'h', 'e', 'l', 'l', 'o', '\0'};

	char str[6] = "hello";

	printf("%s");	使用printf打印字符串的时候,必须碰到 \0 结束。
	

练习:键盘输入字符串,存至str[]中,统计每个字母出现的次数。

for (size_t i = 0; i < 10; i++)
{
	scanf("%c", &str[i]);
}

int count[26] = {0};  // 代表26个英文字母出现的次数。 

for (size_t i = 0; i < 11; i++)
{
	int index = str[i] - 'a';	// 用户输入的字符在 count数组中的下标值。
	count[index]++;
}

for (size_t i = 0; i < 26; i++)
{
	if (count[i] != 0)
	{
		printf("%c字符在字符串中出现 %d 次\n", i+'a', count[i]);
	}
}

示例

int main(void)
{
	char str[6] = { 'h','e','l','l','o','\0' };
	char str2[] = "world"; //等价于 {'w','o','r','l','d','\0'};

	printf("%s\n", str);
	printf("%s\n", str2);

	//统计字符串中每个字符出现的次数
	char str3[100] = { 0 }; //helloworld ——26个英文字母a-z a:97 d:100
	scanf("%s", str3);
	printf("str3 = %s\n", str3);

	int count[26] = { 0 };
	for (int i = 0; i < 11; i++) 
	{
		int index = str3[i] - 'a';//用户输入的字符在count字符中的下标值
		count[index] ++;
	}
	for (size_t i = 0; i < 26; i++)
	{
		if (count[i] > 0) 
		{
			printf("字符%c在字符串中出现%d次\n", 97 + i, count[i]);
		}
	}

	system("pause");
	return EXIT_SUCCESS;
}

字符串获取 scanf:

注意:	1)用于存储字符串的空间必须足够大,防止溢出。 char str[5];

	2) 获取字符串,%s, 遇到空格 和 \n 终止。

借助“正则表达式”, 获取带有空格的字符串:scanf("%[^\n]", str);

示例


int main(void)
{
	char str[11];

	scanf("%[^\n]s", str);
	printf("%s\n", str);

	//借助“正则表达式”scanf("%[^\n]",str); ^表示除XX之外。此处表示接收除\n之外的字符

	system("pause");
	return EXIT_SUCCESS;
}

字符串操作函数:

gets: 从键盘获取一个字符串, 返回字符串的首地址。 可以获取带有 空格的字符串。 【不安全】

	char *gets(char *s);

		参数:用来存储字符串的空间地址。

		返回值:返回实际获取到的字符串首地址。


fgets: 从stdin获取一个字符串, 预留 \0 的存储空间。空间足够读 \n, 空间不足舍弃 \n  【安全】

	char *fgets(char *s, int size, FILE *stream);

		参1:用来存储字符串的空间地址。

		参2:描述空间的大小。

		参3:读取字符串的位置。	键盘 --》 标准输入:stdin

		返回值:返回实际获取到的字符串首地址。


puts:将一个字符串写出到屏幕. printf("%s", "hello"); / printf("hello\n"); / puts("hello");   输出字符串后会自动添加 \n 换行符。

	int puts(const char *s);	

		参1:待写出到屏幕的字符串。

		返回值: 成功:非负数 0。 失败: -1.		


fputs:将一个字符串写出到stdout.输出字符串后, 不添加 \n 换行符。

	int fputs(const char * str, FILE * stream);	

		参1:待写出到屏幕的字符串。		屏幕 --》标准输出: stdout

		参数:写出位置 stdout

		返回值: 成功:0。 失败: -1.


strlen: 碰到 \0 结束。

	size_t strlen(const char *s);

		参1: 待求长度的字符串

		返回:有效的字符个数。

示例1:函数的使用

int main(void)
{
	char str[100];

	printf("获取到的字符串为:%s\n", gets_s(str,100)); 
	// Visual studio中已经没有gets函数,用gets_s代替,多了一个参数代表数目。
	
	//fgets函数写法;安全的,给\0预留位置,空间足够会读\n;
	printf("获取到的字符串为:%s\n", fgets(str, sizeof(str),stdin));

	//puts
	char str1[] = "hello world";
	puts(str1); //等价于 puts("hello world");输出字符串后自动添加\n符;

	//fputs 
	fputs(str1, stdout);//等价于fputs("hello world",stdout); 输出字符串后不添加\n符;
	
	//strlen
	printf("strlen =", strlen(str1));//返回有效的字符个数,到\0终止;
	system("pause");
	return EXIT_SUCCESS;
}

示例2:skrlen的实现逻辑

int main(void)
{
	char str[] = "hello world";
	//fgets(str, 100, stdin);
	
	int i = 0;
	while (str[i] != '\0') 
	{
		i++;
	}
	printf("%d\n", sizeof(str) / sizeof(str[0]));
	printf("%d\n", i);

	system("pause");
	return EXIT_SUCCESS;
}

字符串追加:

char str1[] = "hello";
char str2[] = "world";

char str3[100] = {0};

int i = 0;		// 循环 str1
while (str1[i] != '\0')
{
	str3[i] = str1[i];  // 循环着将str1中的每一个元素,交给str3
	i++;
}					// str3=[h e l l o]
//printf("%d\n", i);  --> 5

int j = 0;		// 循环 str2
while (str2[j]) // 等价于 while(str2[j] !='\0') 等价于 while (str2[j] != 0)
{
	str3[i+j] = str2[j];
	j++;
}					// str3=[h e l l o w o r l d]

// 手动添加 \0 字符串结束标记
str3[i + j] = '\0';

示例


int main(void)
{
	char str1[] = "hello";
	char str2[] = "world";
	char str3[100] = { 0 };

	int i = 0;
	while (str1[i]) //等价于(str1[i] != '\0');等价于(str1[i] != 0);
	{
		str3[i] = str1[i]; //循环着将str1中的每一个元素,交给str3;
		i++; // str3 = “hello”;
	}
	int j = 0;
	while (str2[j]) 
	{
		str3[i + j] = str2[j];
		j++;
	}
	str3[i + j] = '\0';
	fputs(str3,stdout);

	system("pause");
	return EXIT_SUCCESS;
}

函数的作用:

1. 提高代码的复用率

2. 提高程序模块化组织性。

函数分类:

系统库函数: 标准C库。 libc

	1. 引入头文件 --- 声明函数
	
	2. 根据函数原型调用。

用户自定义:

	除了需要提供函数原型之外,还需要提供函数实现。

系统函数如: 随机数:

1. 播种随机数种子: srand(time(NULL));

2. 引入头文件 #include <stdlib.h>  <time.h>

3. 生成随机数: rand() % 100;

函数定义:

包含 函数原型(返回值类型、函数名、形参列表) 和 函数体(大括号一对, 具体代码实现)

形参列表: 形式参数列表。一定包 类型名 形参名。

int addint a, int b, int c)
{
	return a+b+c;
}

int test(char ch, short b, int arr[], int m)

函数调用:

包含 函数名(实参列表);  

int ret = add(10, 4, 28);
	
实参(实际参数): 在调用时,传参必须严格按照形参填充。(参数的个数、类型、顺序)  没有类型描述符

int arr[] = {1, 3, 6};

函数声明:

包含 函数原型(返回值类型、函数名、形参列表) + “;”

要求 在函数调用之前,编译必须见过函数定义。否则,需要函数声明。

int add(int a, int b, int c);


隐式声明:【不要依赖】

	默认编译器做隐式声明函数时,返回都为 int ,根据调用语句补全函数名和形参列表。


#include <xxx.h> --> 包含函数的声明

exit函数: #include <stdlib.h>

return关键字:

	返回当前函数调用,将返回值返回给调用者。

exit()函数:

	退出当前程序。

多文件编程:

将多个含有不同函数功能 .c 文件模块,编译到一起,生成一个 .exe文件。


<>包裹的头文件为系统库头文件。

""包裹的头文件为用户自定义头文件。


防止头文件重复包含:头文件守卫。

	1#pragma once		--- windows中

	2#ifndef __HEAD_H__		<--- head.h

	    #define __HEAD_H__

		.... 头文件内容

	    #endif