四、数组
看任何变量的内存,都是将该变量取地址,拖入内存窗口来看
C语言规定字符串的结束标志位'\0'
1.一维数组
#include<stdio.h>
/*
整型 int 4个字节
浮点型 float 4个字节
字符型 char 4个字节
看任何变量的内存,都是将该变量取地址,拖入内存窗口来看
C语言为了方便操作这些数据,提供了一种构造数据类型——数组。
所谓数组,是指一组具有相同数据类型的数据的有序集合。
声明数组时要遵循以下规则:
(1)数组名的命名规则和变量名的相同,即遵循标识符命名规则。
(2) 在定义数组时,需要指定数组中元素的个数,方括号中的常量表达式用来表示元素的个数,即数组长度。
(3)常量表达式中可以包含常量和符号常量,但不能包含变量。也就是说,C语言不允许对数组的大小做动态定义,
即数组的大小不依赖于程序运行过程中变量的值。
*/
#define N 5
int main()
{
//定义数组就是写一个变量名,后面加上方括号,方括号内写上整型常量
//定义数组的一瞬间,数组占据的空间大小就确定下来了
//数组初始化
int c[N] = { 1,3,5,7,9 };
int a[10] = { 1,3,5,7,9 };
int b[10] = { 0 };
int d[] = { 1,2,3,4 };
return 0;
}
2.一维数组的存储及函数传递-访问越界
访问越界
Run-Time Check Failure #2 - Stack around the variable 'a' was corrupted.
#include<stdio.h>
#include<stdlib.h>
//数组越界
//一维数组的传递
#define N 5
int main()
{
int j = 10;
int a[5] = { 1,2,3,4,5 };//定义数组时,数组长度必须固定
int i = 3;
a[5] = 20;//越界访问,访问了不属于自己的空间
a[6] = 21;
a[7] = 22;//越界访问会造成数据异常
printf("a[4] = %d\n", a[4]);//a[4]发生改变
printf("j = %d\n", j);
return 0;
}
3.一维数组的存储及函数传递
#include<stdio.h>
#include<stdlib.h>
//一维数组的传递,数组长度无法传递给子函数
//c语言的函数调用方式是值传递
//打印数组里的每一个元素,数组在传递时,元素个数传递不过去
void print(int b[],int len)
{
int i ;
for (i = 0; i < len; i++)
{
//printf("b[%d] = %3d\n", i, b[i]);
printf("%3d", b[i]);
}
b[4] = 20;//在子函数中修改数组元素
printf("\n");
}
//数组越界
//一维数组的传递
//访问越界
//Run-Time Check Failure #2 - Stack around the variable 'a' was corrupted.
#define N 5
int main()
{
int j = 10;
int a[5] = { 1,2,3,4,5 };//定义数组时,数组长度必须固定
int i = 3;
//a[5] = 20;//越界访问,访问了不属于自己的空间
//a[6] = 21;
//a[7] = 22;//越界访问会造成数据异常
print(a, 5);
printf("a[4] = %d\n", a[4]);//a[4]发生改变
//printf("j = %d\n", j);
return 0;
}
1 2 3 4 5
a[4] = 20
D:\cbook\第四章 数组\Debug\02.一维数组的存储及函数传递.exe (进程 19572)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
4.字符数组
C语言规定字符串的结束标志位'\0'
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
/*
字符数组
初始化字符数组时,一定要让字符数组的大小比看到的字符串的长度多1
C语言规定字符串的结束标志位'\0'
*/
int main()
{
char a[6] = { 'h','e','l','l','o' };
char c[5] = "how";
printf("%s----%s\n", a, c);//printf的s%,对应后面要写的是字符数组名,字符串常量
//读取字符串
char e[20];
scanf("%s", e);
printf("e = %s\n", e);
char d[20], f[20];
scanf("%s%s", d, f);
printf("%s----%s\n", d, f);
return 0;
}
hello----how
h#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
/*
字符数组
初始化字符数组时,一定要让字符数组的大小比看到的字符串的长度多1
C语言规定字符串的结束标志位'\0'
*/
int main()
{
char a[6] = { 'h','e','l','l','o' };
char c[5] = "how";
printf("%s----%s\n", a, c);//printf的s%,对应后面要写的是字符数组名,字符串常量
//读取字符串
char e[20];
scanf("%s", e);
printf("e = %s\n", e);
char d[20], f[20];
scanf("%s%s", d, f);
printf("%s----%s\n", d, f);
return 0;
}ello
e = hello
hello world
hello----world
D:\cbook\第四章 数组\Debug\03.字符数组.exe (进程 19116)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
5.字符数组的传递
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
/*
* 我们把d称为形参
*/
void print(char d[])
{
int i = 0;
while (d[i]!='\0')//d[i]或者d[i]!=0
{
printf("%c", d[i]);//字符数组去输出某一个元素时,用%c
i++;
}
printf("\n");
//修改字符串数组中的内容,把首字母变大写
d[0] -= 32;
}
int main()
{
char c[10] = "hello";//c里边是10,或者20都可以,只要大于等于6即可
print(c);//我们把c称为实参,调用print函数时,是d=c
printf("%s", c);
return 0;
}
hello
Hello
D:\cbook\第四章 数组\Debug\04.字符数组的传递.exe (进程 13904)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
6.gets和puts
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
/*
* 遇到一个问题, scanf通过%s读取字符串时,
* 当遇到空格以后,就会匹配结束,这样没办法把一行带有空格的字符串存入到一个字符数组中
*/
int main()
{
char c[20];//字符数组的数组名里存放的就是字符数组的起始地址,类型是字符指针
//c是一个字符数组,但是编译器给c内部存了一个值,c里边存储的值得类型是字符指针
//fgets(c, sizeof(c), stdin);//gets(c)是一样的,等价
gets(c);//当一次读取一行时,使用gets
puts(c);//等价于printf("%s\n",c);
return 0;
}
how are you
how are you
D:\cbook\第四章 数组\Debug\05.gets和puts.exe (进程 18868)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
7.str函数使用
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
/*
str 系列字符串操作函数主要包括strlen、strcpy、strcmp、strcat等
strlen函数用于统计字符串长度
strcpy函数用于将某个字符串复制到字符数组中
strcmp函数用于比较两个字符串的大小
strcat函数用于将两个字符串连接到一起
各个函数的具体格式如下所示:
#include <string.h>
size_t strlen(char *str);
char *strcpy(char *to,const char *from);//有const代表这个地方可以放一个字符串常量
int strcmp(const char *str1,const char *str2);
char *strcat(char *str1,const char *str2);
*/
int main()
{
char c[20] = "hello world";
printf("数组c内字符串的长度 = %d\n", strlen(c));
char d[20];
char e[20];
strcpy(d, c);
puts(d);
strcpy(e, "study");
puts(e);
//下面是看strcmp,两个字符串比较,是比较对应字符位置的ASCII码值
int ret = strcmp("hello", "hello");
printf("两个字符串比较后的结果 = %d\n", ret);
int ret1 = strcmp("how", "hello");
printf("两个字符串比较后的结果 = %d\n", ret1);
int ret2 = strcmp("hello", "how");
printf("两个字符串比较后的结果 = %d\n", ret2);
//下面看strcat,拼接两个字符串,目标数组要能够容纳拼接后的字符串
strcat(c, e);
puts(c);
char f[20] = "你好 ";
strcat(f, "世界");
puts(f);
return 0;
}
数组c内字符串的长度 = 11
hello world
study
两个字符串比较后的结果 = 0
两个字符串比较后的结果 = 1
两个字符串比较后的结果 = -1
hello worldstudy
你好 世界
D:\cbook\第四章 数组\Debug\06.str函数使用.exe (进程 3252)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
五、指针
1.指针的本质
取地址操作符为&,也称引用,通过该操作符我们可以获取一个变量的地址值;
取值操作符为*,也称解引用,通过该操作符我们可以得到一个地址对应的数据。
#include<stdio.h>
/*
&符号是取地址,指针变量的初始化一定是某个变量取地址
*/
int main()
{
int i = 5;
int* i_pointer = &i;//整型指针变量,指向整型
printf("sizeof(i_pointer) = %d", sizeof(i_pointer));//4个字节
return 0;
}
sizeof(i_pointer) = 4
D:\cbook\第五章 指针\Debug\01.指针的本质.exe (进程 9092)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
2.引用与解引用
#include<stdio.h>
int main()
{
int i = 10;
int* p = &i;
int* a, * b, * c;//声明三个指针变量
printf("i = %d\n", i);//直接访问
printf("*p = %d\n", *p);//间接访问
return 0;
}
i = 10
*p = 10
D:\cbook\第五章 指针\Debug\02.引用与解引用.exe (进程 22164)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
3.计算n的阶乘
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
/*
Description
利用while或者for循环计算n!的值。提示:n! = 1*2*3...*n
Input
一个正整数n,1≤n≤10。
Output
n!的值。
*/
int print(int m)
{
int sum = 1;
while (m)
{
sum *= m--;
}
return sum;
}
int main()
{
int n;
printf("计算n的阶乘\n");
printf("请输入一个正整数:");
scanf("%d", &n);
int count = print(n);
printf("\n");
printf("n的阶乘为,即%d!=%d\n", n, count);
return 0;
}
计算n的阶乘
请输入一个正整数:5
n的阶乘为,即5!=120
D:\cbook\第五章 指针\Debug\03.计算n的阶乘.exe (进程 12764)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
4.面值100元的人民币换成10元、5元、2元和1元面值的票子
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
/*
Description
某人想将手中的一张面值100元的人民币换成10元、5元、2元和1元面值的票子。
要求换正好40张,且每种票子至少一张。问:有几种换法?
Input
无输入
Output
一个数,表示共有多少种换法
*/
//穷举法,34种
int print()
{
int count = 0;//count代表有多少种换法
int a, b, c, d;//10元,5元,2元,1元分别有多少张
for (a = 1; a <= 10; a++)
{
for (b = 1; b <= 20; b++) {
for (c = 1; c <= 50; c++)
{
for (d = 1; d <= 100; d++) {
if ((a * 10 + b * 5 + c * 2 + d * 1) == 100 && (a + b + c + d) ==40 )
{
count++;//count代表有多少种换法
printf("%d * %d * %d * %d = 100\n", a, b, c, d);
}
}
}
}
}
return count;
}
//枚举法 穷举法
int main()
{
int sum;
printf("面值100元的人民币换成10元、5元、2元和1元面值的票子\n");
sum = print();
printf("面值100元的人民币换成10元、5元、2元和1元面值的票子为:%d个方法\n", sum);
return 0;
}
面值100元的人民币换成10元、5元、2元和1元面值的票子
1 * 5 * 31 * 3 = 100
1 * 6 * 27 * 6 = 100
1 * 7 * 23 * 9 = 100
1 * 8 * 19 * 12 = 100
1 * 9 * 15 * 15 = 100
1 * 10 * 11 * 18 = 100
1 * 11 * 7 * 21 = 100
1 * 12 * 3 * 24 = 100
2 * 2 * 34 * 2 = 100
2 * 3 * 30 * 5 = 100
2 * 4 * 26 * 8 = 100
2 * 5 * 22 * 11 = 100
2 * 6 * 18 * 14 = 100
2 * 7 * 14 * 17 = 100
2 * 8 * 10 * 20 = 100
2 * 9 * 6 * 23 = 100
2 * 10 * 2 * 26 = 100
3 * 1 * 29 * 7 = 100
3 * 2 * 25 * 10 = 100
3 * 3 * 21 * 13 = 100
3 * 4 * 17 * 16 = 100
3 * 5 * 13 * 19 = 100
3 * 6 * 9 * 22 = 100
3 * 7 * 5 * 25 = 100
3 * 8 * 1 * 28 = 100
4 * 1 * 20 * 15 = 100
4 * 2 * 16 * 18 = 100
4 * 3 * 12 * 21 = 100
4 * 4 * 8 * 24 = 100
4 * 5 * 4 * 27 = 100
5 * 1 * 11 * 23 = 100
5 * 2 * 7 * 26 = 100
5 * 3 * 3 * 29 = 100
6 * 1 * 2 * 31 = 100
面值100元的人民币换成10元、5元、2元和1元面值的票子为:34个方法
D:\cbook\第五章 指针\Debug\04.兑换100元人民币.exe (进程 1760)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
5.输入N个数(N小于等于100),输出数字2的出现次数
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
/*
Description
输入N个数(N小于等于100),输出数字2的出现次数;
解题提示:
整型数组读取5个整型数的方法如下:
int a[100];
for(int i=O;i<5;i++){
scanf("%d",&a[i]);
}
Input
输入的格式是两行
第一行输入要输入的元素个数,比如5
第二行输入12232,那么输出结果为3,因为2出现了3次
Output
统计数字2出现的次数
*/
//增量编写法
int main()
{
int n;
int arr[100] = {0};
//int brr[100];
printf("要输入的元素个数:");
scanf("%d", &n);//接下来要输入多少个元素
printf("请输入%d个元素:",n);
for (int i = 0; i < n; i++)
{
//scanf("%d", &brr[i]);//如何往数组里元素读入数据
int m;
scanf("%d", &m);
arr[m-1]++;
}
printf("统计数字2出现的次数为:%d次", arr[2 - 1]);
return 0;
}
要输入的元素个数:5
请输入5个元素:1 2 2 3 2
统计数字2出现的次数为:3次
D:\cbook\第五章 指针\Debug\05.某个数字出现的次数.exe (进程 5992)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
要输入的元素个数:10
请输入10个元素:1 2 3 5 6 2 9 2 2 2
统计数字2出现的次数为:5次
D:\cbook\第五章 指针\Debug\05.某个数字出现的次数.exe (进程 21180)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
6.增量编写法–统计2的次数
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
//增量编写法
int main()
{
int n;
int arr[100];
printf("要输入的元素个数:");
scanf("%d", &n);//接下来要输入多少个元素
printf("请输入%d个元素:", n);
int i;
for (i = 0; i < n; i++)
{
scanf("%d", &arr[i]);//如何往数组里元素读入数据
}
int count = 0;
for (i = 0; i < n; i++)//统计2出现的次数
{
if (arr[i] == 2)
{
count++;
}
}
printf("统计数字2出现的次数为:%d次", count);
return 0;
}
要输入的元素个数:5
请输入5个元素:1 2 2 3 2
统计数字2出现的次数为:3次
D:\cbook\第五章 指针\Debug\06.增量编写法.exe (进程 3388)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
7.字符串逆转比较
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
/*
Description
读取一个字符串,字符串可能含有空格,将字符串逆转,
原来的字符串与逆转后字符串相同,输出0,
原字符串小于逆转后字符串输出-1,
大于逆转后字符串输出1。
例如输入hello,逆转后的字符串为olleh,因为hello小于olleh,所以输出-1
lnput
输入一个字符串,例如hello,当如输入的字符串也可能是how are you,含有空格的字符串
Output
输出是一个整型数,如果输入的字符串是hello,那么输出的整型数为-1
*/
int main()
{
char c[100];
printf("请输入一个字符串:\n");
gets(c);//当一次读取一行时,使用gets
printf("数组c内字符串的长度 = %d\n", strlen(c));
printf("反转之前C:");
puts(c);
printf("\n");
int m = strlen(c)-1;
char d[100];
strcpy(d, c);
for (int i = 0; i < m; i++, m--)
{
char tmp = c[i];
c[i] = c[m];
c[m] = tmp;
}
printf("反转之后C:");
puts(c);
printf("\n");
int count = strcmp(d, c);
if (count == -1)
{
printf("输入%s,逆转后的字符串为%s,因为原字符串%s小于逆转后的字符串%s,所以输出%d", d, c, d, c, count);
}
else if (count == 1)
{
printf("输入%s,逆转后的字符串为%s,因为原字符串%s大于逆转后的字符串%s,所以输出%d", d, c, d, c, count);
}
else {
printf("输入%s,逆转后的字符串为%s,因为原字符串%s等于于逆转后的字符串%s,所以输出%d", d, c, d, c, count);
}
return 0;
}
请输入一个字符串:
hello
数组c内字符串的长度 = 5
反转之前C:hello
反转之后C:olleh
输入hello,逆转后的字符串为olleh,因为原字符串hello小于逆转后的字符串olleh,所以输出-1
D:\cbook\第五章 指针\Debug\07.字符串逆转比较.exe (进程 15164)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
请输入一个字符串:
hello world
数组c内字符串的长度 = 11
反转之前C:hello world
反转之后C:dlrow olleh
输入hello world,逆转后的字符串为dlrow olleh,因为原字符串hello world大于逆转后的字符串dlrow olleh,所以输出1
D:\cbook\第五章 指针\Debug\07.字符串逆转比较.exe (进程 11260)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
请输入一个字符串:
hahaahah
数组c内字符串的长度 = 8
反转之前C:hahaahah
反转之后C:hahaahah
输入hahaahah,逆转后的字符串为hahaahah,因为原字符串hahaahah等于于逆转后的字符串hahaahah,所以输出0
D:\cbook\第五章 指针\Debug\07.字符串逆转比较.exe (进程 10716)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
8.fgets和gets
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
//fgets相对于gets去读取标准输入时,会把\n放到字符数组中
int main()
{
char c[100], d[100];
printf("请输入一个字符串:\n");
//gets(c);//当一次读取一行时,使用gets
fgets(c, sizeof(c), stdin);//stdin标准输入
int len = strlen(c);
c[len - 1] = '\0';
//puts(c);//用来调试的
int i, j;
for (i = strlen(c) - 1, j = 0; i >= 0; i--, j++)//字符串翻转
{
d[j] = c[i];
}
d[j] = '\0';
puts(d);//得到的d对不对
int result = strcmp(c, d);
if (result < 0) {
printf("%d\n", -1);
}
else if (result > 0) {
printf("%d\n", 1);
}
else {
printf("%d\n", 0);
}
return 0;
}
请输入一个字符串:
hello
olleh
-1
D:\cbook\第五章 指针\Debug\08.fgets和gets.exe (进程 19660)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
请输入一个字符串:
cba
abc
1
D:\cbook\第五章 指针\Debug\08.fgets和gets.exe (进程 6276)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
请输入一个字符串:
aba
aba
0
D:\cbook\第五章 指针\Debug\08.fgets和gets.exe (进程 5980)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
9.指针的传递
#include<stdio.h>
#include<stdlib.h>
void change(int j)
{
j = 5;
}
int main()
{
int i = 10;
printf("before change i = %d\n", i);
change(i);
printf("after change i = %d\n", i);
return 0;
}
before change i = 10
after change i = 10
D:\cbook\第五章 指针\Debug\09.指针的传递.exe (进程 20128)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
10.指针的传递–值传递–地址传递
#include<stdio.h>
#include<stdlib.h>
/*
值传递
*/
void change(int j)//j称为形参
{
printf("值传递\n");
j = 5;
}
/*
地址传递
*/
void rechange(int *m)//j称为形参,m=&i
{
printf("地址传递\n");
*m = 5;//指针的间接访问
}
int main()
{
int i = 10;//i是局部变量
printf("before change i = %d\n", i);
change(i);//函数调用是,把i称为实参;值传递
printf("after change i = %d\n", i);
rechange(&i);
printf("after rechange i = %d\n", i);
return 0;
}
before change i = 10
值传递
after change i = 10
地址传递
after rechange i = 5
D:\cbook\第五章 指针\Debug\09.指针的传递.exe (进程 14144)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
11.指针的偏移
#include<stdio.h>
#include<stdlib.h>
/*
* 指针的偏移
*
* 数组是特殊的,不能和整型变量,浮点型,字符型变量类比
*
* 数组名 a 类型是数组,a里边存了一个值,是地址值,是数组的起始地址,记住
*
* 引发了异常:读取访问权限冲突。
* P是OxCCCCCCCC。
*
* 内存分为3种权限,掌握两种,可读,可写
* 出现上述异常是因为对应内存位置不可读
*
*/
int main()
{
int a[5] = { 1,2,3,4,5 };
//int* p=0xcccccccc;//对一个指针变量进行取值,得到的类型是其基类型
int* p;//对一个指针变量进行取值,得到的类型是其基类型
p = a;
printf("*p = %d\n", *p);
for (int i = 0; i < sizeof(a)/sizeof(a[0]); i++)
{
printf("a[%d]=%d\n", i, *(p + i));
}
}
*p = 1
a[0]=1
a[1]=2
a[2]=3
a[3]=4
a[4]=5
D:\cbook\第五章 指针\Debug\10.指针的偏移.exe (进程 22380)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
12.指针与自增、自减
#include<stdio.h>
#include<stdlib.h>
//只有比后增优先级高的操作符,才会作为一个整体,如()、[]
int main()
{
int a[3] = { 2,7,8 };
int *p;//对一个指针变量进行取值,得到的类型是其基类型
int j;
p = a;//让指针变量p,指向数组的开头
//j = (*p)++;//j=*p;(*p)++
j = *p++;//j=*p;p++,任何时候都是把后加加去掉,第二步另外一个运算符看优先级是否高于++;
//先把*p的值赋给j,然后对p加1
printf("a[0]=%d,a[1]=%d,a[2]=%d,j=%d,*p=%d\n", a[0], a[1], a[2], j, *p);//{2,7,8},2,7
j = p[0]++;//先把p[0]赋给j,然后对p[0]加1
printf("a[0]=%d,a[1]=%d,a[2]=%d,j=%d,*p=%d\n", a[0], a[1], a[2], j, *p);//{2,8,8},7,8
j = (*p)++;
printf("a[0]=%d,a[1]=%d,a[2]=%d,j=%d,*p=%d\n", a[0], a[1], a[2], j, *p);//{2,9,8},8,9
return 0;
}
a[0]=2,a[1]=7,a[2]=8,j=2,*p=7
a[0]=2,a[1]=8,a[2]=8,j=7,*p=8
a[0]=2,a[1]=9,a[2]=8,j=8,*p=9
D:\cbook\第五章 指针\Debug\11.指针与自增、自减.exe (进程 18756)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
13.指针与一维数组
#include<stdio.h>
#include<stdlib.h>
//指针的偏移
//数组名作为实参传递给子函数时,是弱化为指针的
void change(char *d)//d为形参
{
*d = 'H';
d[1] = 'E';//*(d + 1) = 'E';
*(d + 2) = 'L';
}
//指针与一维数组
//函数调用的本质是值传递(实参赋值给形参)
//数组传递是弱化为指针
int main()
{
char c[10] = "hello";
change(c);//c为实参
printf("c = %s\n", c);
puts(c);
return 0;
}
c = HELlo
HELlo
D:\cbook\第五章 指针\Debug\12.指针与一维数组.exe (进程 5612)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
14.malloc动态内存申请
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
/*
* C语言的数组长度固定是因为其定义的整型、浮点型、字符型变量、数组变量都在栈空间中,而栈空间的大小在编译时是确定的。
* 如果使用的空间大小不确定,那么就要使用堆空间。
*
* 申请5*sizeof(int)=20字节
*
* 数组一开始定义好就确定下来了,数组是放在栈空间
*
* 程序是放在磁盘上的有序的指令集合
*
* 程序启动起来时才叫进程
*
* malloc可以帮我们实现动态数组
*/
int main()
{
int i;//申请多大的空间
char *p;
scanf("%d", &i);//输入需要申请的空间大小
p = (char *)malloc(i);//malloc申请空间的单位是字节
strcpy(p, "malloc success");
puts(p);
//释放空间,p的值必须和最初malloc返回的值一致
free(p);//free时必须使用malloc申请时返回的指针值,不能进行任何偏移
p = NULL;//如果不把p值为NULL,把p称为野指针
return 0;
}
20
malloc success
D:\cbook\第五章 指针\Debug\13.malloc动态内存申请.exe (进程 4388)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
15.栈空间与堆空间的差异
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//栈空间
char* print_stack()
{
printf("-----栈空间-----\n");
char c[] = "I am print_stack";
puts(c);//能正常打印
return c;
}
//堆空间
char* print_malloc()
{
printf("-----堆空间-----\n");
char* p = (char*)malloc(20);
strcpy(p, "I am print_malloc");
puts(p);
return p;
}
int main()
{
char *p;
//数据放在栈空间
p = print_stack();//栈空间会随着函数的执行结束而释放掉
//puts(p);//打印异常,出现乱码,打印不出来
//数据存放在堆空间
p = print_malloc();//堆空间不会随着子函数的结束而释放,必须自己free
puts(p);
return 0;
}
-----栈空间-----
I am print_stack
-----堆空间-----
I am print_malloc
I am print_malloc
D:\cbook\第五章 指针\Debug\14.栈空间与堆空间的差异.exe (进程 11788)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
16.malloc实现动态数组
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
/*
Description
输入一个整型数,然后申请对应大小空间内存,然后读取一个字符串,
字符串的输入长度小于最初输入的整型数大小,最后输出输入的字符串即可
(无需考虑输入的字符串过长,超过了内存大小);
注意下面问题:
char *p;
scanf("%d",&n);
p=malloc(n);
scanf("%c",&c);/注意在scanf和gets中间使用scanf("%c",&c),去除换行gets(p);
Input
一个整型数和一个字符串,例如和
10
hello
Output
输出输入的字符串,上面输入的是hello,那么输出hello
*/
//malloc可以帮我们实现动态数组
int main()
{
int i;//申请多大空间
scanf("%d", &i);//读取一个整型数
char* p;
p = (char*)malloc(i);//malloc申请空间的单位是字节,不进行强制类型转换会有警告
char c;
scanf("%c", &c);//为了去除缓冲区里的\n,VS可以用rewind,oj不行,不能用rewind
gets(p);
puts(p);
return 0;
}
10
hello
hello
D:\cbook\第五章 指针\Debug\15.malloc实现动态数组.exe (进程 8012)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
17.字符指针与字符数组的初始化
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char *p = "hello";//把字符串型常量"hello"的首地址赋给p
char c[10] = "hello";//等价于strcpy(c,"hello");
printf("c[0]=%c\n", c[0]);
printf("p[0]=%c\n", p[0]);
c[0] = 'H';
printf("c[0]=%c\n", c[0]);
printf("p[0]=%c\n", p[0]);
//p[0] = 'H';//不可以对常量区数据进行修改
p = "world";//将字符串world的地址赋给p
//c = "world";//非法
printf("p[0]=%c\n", p[0]);
return 0;
}
c[0]=h
p[0]=h
c[0]=H
p[0]=h
p[0]=w
D:\cbook\第五章 指针\Debug\16.字符指针与字符数组的初始化.exe (进程 14444)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
18.二级指针的传递-了解
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
//了解
//二级指针的初始化一定是某一个一级指针取地址
void change(int **p, int *pj)
{
int i = 5;
*p = pj;
}
//要想在子函数中改变一个变量的值,必须把该变量的地址传进去
//要想在子函数中改变一个指针变量的值,必须把该指针变量的地址传进去
int main()
{
int i = 10, j = 5;
int *pi, *pj;
pi = &i;
pj = &j;
printf("i=%d,*pi=%d,*pj=%d\n", i, *pi, *pj);//等于i=10,*pi=10,*pj=5
change(&pi, pj);
printf("after change i=%d,*pi=%d,*pj=%d\n", i, *pi, *pj);//after change i=10,*pi=5,*pj=5
return 0;
}
i=10,*pi=10,*pj=5
after change i=10,*pi=5,*pj=5
D:\cbook\第五章 指针\Debug\17.二级指针的传递.exe (进程 11068)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .