笔记:二维数组,字符串,指针
#mark- 01-二维数组基本概念
//问题:什么是二维数组?二维数组的格式?二维数组如何存储?二维数组是如何遍历?
1.二维数组: 数组中的每一个元素又是一个数组, 那么这个数组就称之为二维数组
2.二维数组格式:
元素类型 数组名称[一维数组的个数][每个一维数组的元素个数];
元素类型 数组名称[行数][列数];
元素类型: 说明二维数组中每个一维数组存储什么类型的数据
一维数组的个数: 说明二维数组有多少个元素
每个一维数组的元素个数 : 说明二维数组中每一个一维数组的元素个数
3.遍历二维数组
// 思路: 1.取出二维数组的每一个元素(取出二维数组中的一维数组)
// 2.遍历一维数组
for (int i = 0; i < 2; i++) { // 0 , 1
for (int j = 0; j < 3; j++) { // 0 , 1 , 2
printf("name[%i][%i] = %c\n", i, j, names[i][j]);
}
}
#mark- 02-二维数组注意点
//问题:二维数组如何初始化?
二维数组的多种初始化方式
// 1.定义的同时初始化
int names[2][3] =
{
{'l', 'n', 'j'},
{'x', 'm', 'g'}
};
// 2.先定义再初始化
int names2[2][3];
names2[0][0] = 'l';
names2[0][1] = 'n';
names2[0][2] = 'j';
names2[1][0] = 'x';
names2[1][1] = 'm';
names2[1][2] = 'g';
// 3.完全初始化
int names3[2][3] =
{
{'l', 'n', 'j'},
{'x', 'm', 'g'}
};
// 4.不完全初始化
int names4[2][3] =
{
{'l', 'n'},
};
// 5.省略元素个数的两种写法
// 明确的告诉二维数组, 我们有2个一维数组
char names5[2][3] =
{
'l', 'n', 'j',
'x', 'm', 'g'
};
// 没有告诉二维数组我们有几个一维数组
// 如果在"定义的同时"进行初始化, 那么一位数组的个数可以省略 \
系统会自动根据每一个一维数组能够存放多少个元素, 自动根据初始化的值推断出二维数组中一共有多少个元素(多少个一维数组)
char names6[][3] =
{
'l', 'n', 'j',
'x', 'm', 'g',
'n', 'b'
};
// 6.错误写法
// 注意点: 每个一维数组的元素个数不能省略
/*
int names7[2][] =
{
{'l', 'n', 'j'},
{'x', 'm', 'g'}
};
*/
/*
// 搞不清楚应该分配多大的存储空间, 以及搞不清楚应该把哪些数据赋值给第一个数组, 以及哪些数据赋值给第二个数组
int names7[2][] =
{
'l', 'n', 'j',
'x', 'm', 'g'
};
*/
#mark- 03-二维数组和函数
//问题:二维数组作为函数参数传递?
//数组传递,值传递的区别
//二维数组可以省略一维数组的个数,不可省略一维数组有多少个元素
1.二维数组名称作为函数参数传递, 是传递的地址
change2(names);
void change2(char values[2][3])
{
values[0][1] = 'w';
printf("我执行了\n");
}
2.// 以后只要看到函数的参数是一个数组, 那么就是地址传递
// 在函数中修改形参的值会影响到参数
names[0] == 一维数组
change3(names[0]);
void change3(char values[])
{
values[0] = 'Q';
printf("我执行了\n");
}
3.// 基本数据类型
names[0][0] == 一维数组的一个元素 == 值
change4(names[0][0]);
void change4(char value)
{
value = 'E';
printf("我执行了\n");
}
#mark- 04-字符串基本概念
//问题:什么是字符串?如何初始化字符串?输出字符串?
//问题2:%s的原理?
1.用双引号引起来的就是字符串
2.字符串变量和普通的字符数组的区别
char str[] = "lnj"; // 字符串变量 l n j \0
// 字符数组 , 这个并不是字符串, 而是字符数组
char charValues[] = {'l', 'n', 'j'};
3.//C语言规定, 字符串必须以\0结尾(作为字符串的结束符号), 所以字符串变量的元素个数比字符数组的元素个数多一个 \0
4.//字符串变量输出的的原理
%s的原理, 从传入的"地址"开始逐个取出, 直到遇到"\0"为止
5.注意:字符串以\0结尾, 没有\0就不是字符串
6.//字符串的本质就是数组
char str6[] = "lnj";
str6[1] = 'y';
printf("%s", str6);
#mark- 05-子符串常用方法1
//问题:如何输出字符串?
//问题1:printf和puts 函数的区别
1.printf和puts 函数的区别
printf函数
弊端 : 如果想要换行, 必须加上\n
优点 : 可以自定义格式化需要输出的字符串, 也就是可以按照我们需要的格式来输出
puts函数
优点: 可以自动换行
缺点: 不可以自定义格式, 只能原样输出
//问题2:利用scanf接收字符串的有什么注意点?
2.输入字符串
1)利用scanf接收字符串的注意点
scanf接收字符串, 会以空格 , tab, 回车作为结束符号, 也就是说利用scanf接收字符串时, 字符串中不能出现空格, tab, 回车
2)利用gets接收字符串优点
优点: 如果利用gets接收字符串 , 可以在字符串中输入空格, tab
//问题3:如何计算字符串长度?
3.使用strlen 计算字符串长度
strlen的原理: 从传入的地址开始逐个取出字符串, 每取出一个就让计数器+1. 直到遇到\0为止
#mark- 06-字符串常用方法2
//问题:字符串如何拼接,拷贝,比较?
1.字符串拼接原理
strcat()
// 原理 : 首先遍历第一个字符串,直到遇到\0为止, 然后取出第二个字符串中的字符, 从\0的位置开始添加, 添加完毕之后再在最后添加一个\0
2.字符串拷贝原理
strcpy()
逐个替换, 拷贝了几个就替换几个
//strcpy函数会将源的数据拷贝到目标中, 并且会覆盖掉目标中原有的数据
// 目标的容积必须能够存放拷贝的数据, 如果容积不够会报错
3.字符串比较
strcmp()
// strcmp的原理: 取出字符串中的每一个字符进行逐个比较, 如果发现不相等就不会继续往下比较
#mark- 07-字符串练习
// 编写一个函数char_contains(char str[],char key), 如果字符串str中包含字符key则返回数值1,否则返回数值0
// 给你一个字符串和一个key, 要求从字符串中找出key, 如果找到就返回1没有找到就返回0
#mark- 08-字符串数组
//问题:什么是字符串数组?
// 如果想存储一堆字符串那么可以使用字符串数组
// 说白了字符串数组就是二维数组
#mark- 09-指针基本概念
//问题:什么是指针?格式?保存的是什么数据?指针有什么作用?
指针就是专门用于保存地址的
1.定义指针变量
普通变量:
数据类型 变量名称;
指针变量:
数据类型 * 变量名称;
数据类型 : 说明将来指针变量能够保存什么类型的变量的地址
注意: 指针变量是什么类型, 那么将来就只能保存什么类型变量的地址,
例如: 指针变量是int类型, 那么将来就只能保存int类型变量的地址
* : 没有任何特殊含义, 仅仅是为了标示这是一个指针变量
变量名称 : 用于区分不同的变量
2.指针 , 在64位编译器下占用8个字节
3.注意:指针变量前的*号代表访问指针变量指向的那一块存储空间
4.指针定义时,一定要给一个地址
int a = 10;
float b = 9.9;
int *p = &a;//指针定义时,初始化只能是地址
*p = 22;//指针定义后,给带星指针赋值,只能是数值
p = &b; //给不带星指针赋值,一定是地址
printf("a = %d, b = %d", a, *p);
#mark- 10-指针练习1
//问题:如何使用指针交换两个变量的值?
// 定义一个函数交换两个变量的值
注意:画图分析内存
和数组进行对比
void swap(int *v1, int *v2)
// int *v1 = &a, int *v2 = &b; v1 = 0ffc13 v2 = 0ffc9
// *v1 == a *v2 == b
{
int temp = *v1; // int temp = 0ffc13
*v1 = *v2;
*v2 = temp;
}
#mark- 11-指针练习2
//问题:如何通过指针修改函数外部变量?
// 要求:定义一个函数, 传递三个值, 返回这三个值得和,差,平局值
注意:画图分析
int demo(int v1, int v2, int v3, int *p1, int *p2)
{
int sum = v1 + v2 + v3;
*p1 = sum;
int m = v1 - v2 - v3;
*p2 = m;
int average = sum / 3;
return average;
}
#mark- 12-指针注意点
//问题:指针的几个注意点?
// 1.指针只能保存地址
int *p = 200;
printf("%i\n", *p);
// 2.同一个变量可以有多个指针指向它
int num = 10;
int *p = #
// *p == num
// num = 55;
*p = 55;
int *p1 = p;
*p1 = 100;
int *p2 = #
printf("%i\n", *p);
// 3.指针的指向可以修改
int a = 10;
int b = 5;
int *p = &a;
*p = 88;
p = &b;
*p = 44;
printf("%i\n", a);
printf("%i\n", b);
// 4.不要访问野指针
// 没有赋值的指针, 我们称之为野指针
// int *p;
int *p = NULL; // 0
printf("%i\n", *p);
// 5.指针类型是什么类型, 就只能指向什么类型的数据
int num = 10;
char charValue = 'l';
double doubleValue = 9.9;
// int *p = #
// int *p = &charValue;
// int *p = &doubleValue;
double *p = &doubleValue;
printf("%lf\n", *p);
#mark- 13-多级指针
//问题:如何使用多级指针?
多级指针的操作, 最简单的方式, 就是通过几颗星来存储, 就通过几颗星来访问
还有一种方式就是画图, 看图片中有几个箭头, 有几个简单就用几颗星来访问
#mark- 14-指针为什么要分类型
//指针为什么要分类型?
// 因为当我们利用指针去取值的时候, 系统就会自动根据指针的类型来确定应该取对少个字节中的值