C/C++不常用知识点总结
一、C/C++不常用的知识点总结
1.1 逗号表达式
int a;
a = (3, 4); //========> a = 4; 取逗号后面的一个元素
a = 3, 4; //========> a = 3; ‘=’优先级高于‘,’
// 逗号运算符的优先级较低
试分析下面代码中的z,x,y的值是多少?
int main()
{
int x, y, z;
x=y=1;
z=x++,y++,++y; // ‘=’优先级高于‘,’,z = x = 1;
printf("%d,%d,%d\n", x, y, z);
return 0;
}
// x=2, y=3, z=1
试分析下面代码中的z,x,y的值是多少?
int main()
{
int x, y, z, m=0;
x = y = 1;
m = (z = x++, y++, ++y); //m = (1, 1, 3) ====>m = 3
m = (++y, y++, z = x++); //m = (4, 4, 2)
m = (++y, z = x++, y++); //m = (6, 3, 6)
printf("%d,%d,%d, %d\n", x, y, z, m); // x = 4, y = 7, z= 3, m=6;
return 0;
}
1.2 scanf_s()和printf()的返回值
scanf_s()返回正确输入元素的个数,printf()返回输出字符的个数。
#include<stdio.h>
int main()
{
int x, y, z, u;
u = printf("Input two integers:\n"); // u = 20, (汉字占两个字符)
z = scanf("%d %d", &x, &y); // 正确输入两个整数时,会返回2
puts("printf的返回值:");
printf("%d\n", u);
puts("scanf_s的返回值:");
printf("%d\n", z);
return 0;
}
scanf_s()函数与scanf()函数的区别:
(1) scanf_s(“%s”, s, 6)的最后一个参数为输入缓冲区的大小,表示最多读取6-1个字符, s[5]要放’\0’,也即scanf_s()函数会检查边界,不会出现内存访问越界的情况。
(2) scanf()在读取时不检查边界,所以可能会造成内存访问越界,例如分配了4字节的空间但是读入了6字节数据,具体见如下代码所示。
char s[4];
scanf("%s", s); // 输入:abcdef
// 输入:abcdef 时, def部分会被写到别的空间上去。
1.3 scanf()+while()示例
// 提示用户输入一个数字,用户输入字符怎么办?
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
int num;
char ch;
printf("Please enter an integer:\n");
while (scanf("%d", &num) != 1) // 未正确输入一个整数,则继续执行。
{
while ((ch = getchar()) != '\n') // 清空缓冲区中的字符
{
putchar(ch);
}
printf(" is not an intger.\nPlease enter an intger value, such"
"as 25, -1, 3. : _\b");
}
printf("%d\n", num);
return 0;
}
1.4 浮点型也可以这样初始化
float m = .2, n = .8e5, k = 100.; //后面加上空格之后就无法正常编译
1.5 用#define定义一个函数
#include<stdio.h>
#define SQUARE(x) x*x
int main()
{
int a = 5;
printf("SQUARE(a): %d\n", SQUARE(a));
printf("SQUARE(a+1): %d\n", SQUARE(a + 1)); //想一下为什么输出值是11
return 0;
// SQUARE(a + 1)等价于==>a+1*a+1=5+1*5+1=11
}
二、数组
2.1 数组的定义初始化
数组的定义:
int arr[5]; char ch[3];
初始化:
a[5] = {1,2,3,4,5}; ch[3] = “abc”;
定义时初始化:
int a[5] = {1,2,3,4,5}; char ch[3] = “abc”;
int a[] = {1,2,3,4,5}; char ch[] = “abc”;
注意:
int char ch = "hdfkakfafd"; 编译器会自动在末尾添上'\0',但是在计算字符串的长度时,并不会计算’\0’;
int str[3] = {'a', 'b', 'c'}; 则不会在末尾添加'\0';
2.2 用sizeof()求出数组长度
eg:利用sizeof()对数组赋初值
#include<stdio.h>
int main()
{
int arr[4] = {0, 0, 0, 0};
printf("请输入%d个数:\n", (sizeof(arr) / sizeof(int))); //计算数组的长度
for (int i = 0; i < (sizeof(arr) / sizeof(int)); i++)
{
scanf_s("%d", &arr[i]);
}
putchar('\n');
puts("输出:");
for (int i = 0; i < (sizeof(arr) / sizeof(int)); i++)
{
printf("%d ", arr[i]);
}
return 0;
}
2.3 变长数组
变长数组需要引入头文件<stdlib.h>—>malloc()/calloc()
利用malloc()和calloc()创建一维边长数组
// 利用malloc()和calloc()创建一维边长数组
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* arry = NULL; // 初始化数组指针
int arr_len; // 数组长度
int i;
printf("请输入数组的长度:\n");
scanf_s("%d", &arr_len);
printf_s("%d\n", arr_len * sizeof(int));
arry = (int*)malloc(arr_len * sizeof(int)); // array指向长度为arr_len的整型数组首地址
//arry = (int*)calloc(arr_len , sizeof(int));
if (arry == NULL)
{
printf("分配内存失败\n");
}
else {
printf("请输入%d个数:\n", arr_len);
for (i = 0; i < arr_len; i++)
{
scanf_s("%d", &arry[i]);
}
putchar('\n');
puts("输出:");
for (i = 0; i < arr_len; i++)
{
printf_s("%d\t", *(arry+i));
}
}
free(arry);
return 0;
}
利用malloc()和calloc()创建二维边长数组
// 实质还是一维数组
#include<stdio.h>
#include<stdlib.h>
int main(){
int row, col;
scanf("%d %d", &row, &col);
int *arr = (int *)malloc(row*col*sizeof(int)); // arrr指向长度为row*col的整型数组首地址, 实质为一维数组
if (arr){
for (int i=0; i<row; i++){
for (int j=0; j<col; j++){
//scanf("%d", arr + i*col +j);
*(arr +i*col +j) = i*col +j;
}
}
// 输出
for (int i=0; i<row; i++){
for (int j=0; j<col; j++){
//scanf("%d", arr + i*col +j);
printf("%d\t", *(arr + i*col +j));
}
puts("");
}
}
else puts("分配内存失败!");
free(arr);
return 0;
}
// 利用二级指针和一级指针开辟二维数组
#include<stdio.h>
#include<stdlib.h>
int main()
{
int *adr_l = NULL, **adr_r = NULL;
int row, col, i = 0, j = 0;
printf("Please input the length of row and col:");
scanf("%d %d",&row,&col);
//adr_l = (int *)calloc(len_l, sizeof(int));
adr_r = (int **)calloc(row, sizeof(int)); // 指向行的
for(i = 0; i < row; i++)
{
adr_r[i] = (int *)calloc(col,sizeof(int)); // 指向列
}
for(i = 0; i < row; i++)
{
for(j = 0; j < col; j++)
{
adr_r[i][j] += (j + 1);
printf("%2d",adr_r[i][j]);
}
printf("\n");
}
for(i = 0; i < row; i++)
{
free(adr_r[i]);
} free(adr_r);
return 0;
}
// 二级指针为指向指针的指针, 一级指针存放的是变量的地址,而二级指针则是存放的一级指针的地址。
// calloc()创建的数组时,会将数组元素初始化为0。
// malloc()创建数组时,则是随机初始化元素。
2.3 十大经典排序
冒泡排序
// 对数组值操作
#include<stdio.h>
int main()
{
int arr[] = { 1, 23, 0, -1, 90, 9, 34, 7 };
int temp;
for (int i = 0; i < (sizeof(arr) / sizeof(int)); i++)
{
printf("%d\t", arr[i]);
}
putchar('\n');
for (int i=0; i<(sizeof(arr)/sizeof(int)); i++)
{
for (int j=i+1; j < (sizeof(arr) / sizeof(int)); j++)
{
if (arr[i] > arr[j])
{
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
printf("%d\t", arr[i]);
}
}
选择排序
// 找到最小值索引,对数组索引操作
#include<stdio.h>
int main()
{
int arr[] = { 1, 23, 0, -1, 90, 9, 34, 7 };
int temp, minindex;
for (int i = 0; i < (sizeof(arr) / sizeof(int)); i++)
{
printf("%d\t", arr[i]);
}
putchar('\n');
for (int i=0; i<(sizeof(arr)/sizeof(int)); i++)
{
minindex = i;
for (int j=i+1; j < (sizeof(arr) / sizeof(int)); j++)
{
if (arr[j] < arr[minindex])
{
minindex = j;
}
}
temp = arr[i];
arr[i] = arr[minindex];
arr[minindex] = temp;
printf("%d\t", arr[i]);
}
}
插入排序
#include<stdio.h>
int main()
{
int arr[] = { 1, 23, 0, -1, 90, 9, 34, 7 };
int current, pre_index; // current 表示当前值,pre_index表示当前值前面值的索引
int i, j;
// 排序前
for (i = 0; i < (sizeof(arr) / sizeof(int)); i++)
{
printf("%d\t", arr[i]);
}
putchar('\n');
// 插入排序
for (i = 1; i < (sizeof(arr) / sizeof(int)); i++)
{
pre_index = i - 1; // 当前值前一个值的索引
current = arr[i]; // 当前值
while (arr[pre_index] > current && pre_index >= 0) // 当数组中前一个值大于当前值或pre_index>=0就继续往找
{
arr[pre_index + 1] = arr[pre_index]; // 将数组前面所有大于当前值的位置顺次往后移动一位
pre_index--; // 继续往前找
}
arr[pre_index + 1] = current; // 将当前值插入到pre_index+1位置处
}
// 插入排序后
for (int i = 0; i < (sizeof(arr) / sizeof(int)); i++)
{
printf("%d\t", arr[i]);
}
putchar('\n');
return 0;
}
2.4 找出数组中重复数字
题目描述:
在一个长度为n的数组nums里的所有数字都在0~n-1范围内。数组的某些数字是重复的,但是不知道有几个数字重复,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例:
输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 3
// 利用数组元素与下标之间的映射关系
#include<stdio.h>
int main()
{
int nums[] = {2, 3, 1, 0, 2, 5, 3}; // 输入数组
int re_nums[100], temp = 0, len=0; // re_nums[]存放重复元素的数组, temp为临时变量, len统计重复元素的个数
// 打印输入数组
for (int i=0; i<sizeof(nums)/sizeof(int); i++){
printf("%d ", nums[i]);
}
putchar('\n' );
// 输入数组的范围为0~n-1, 可利用数组元素与下标之间的映射关系查找重复元素
for (int i=0; i<(sizeof(nums)/sizeof(int)); i++){ // 遍历输入数组中的元素
while (nums[i] != i) { // 当前索引与索引对应的元素值不相等时,执行。
if (nums[nums[i]] != nums[i]){ // 如果以nums[i]为索引的元素(nums[nums[i]])不等于时,执行。
temp = nums[nums[i]];
nums[nums[i]] = nums[i]; // 将arr[i]放置到以arr[i]为索引的位置处
nums[i] = temp; // 将nums[nums[i]]的值放置在以i为索引的位置处
}else { // 找到重复元素
re_nums[len++] = nums[i]; // 将重复元素放置到相应数组中
break; // 找到重复元素后必须跳出while()循环,否则会一直执行rec_nums[len++] = nums[i];
}
}
printf("%d ", nums[i]);
}
// 输出重复元素
putchar('\n');
for (int i = 0; i<len; i++) {
printf("%d ", re_nums[i]);
}
return 0;
}
三、指针
3.1 指针的定义和初始化
指针也是变量,它是用来存储地址的变量,指针变量本身也有地址。
//指针的定义:
int *p;
//初始化:
int a = 3; p = &a;
//同时也可以在定义时声明:
int *p = &a;
//指针数组:
int *p[3] //指针数组,[]的优先级高于*
int (*p)[3] //指向列为3的二维数组指针
3.2 指针与二维数组的关系
#include<stdio.h>
int main()
{
int a[4][2]={{2,4},{6,8},{1,3},{5,7}};
int(*p)[2];
p = a;
printf(" a = %p, a+1 = %p\n",a, a+1);
printf(" p = %p, p+1 = %p\n", p, p + 1);
printf("a[0] = %p,a[0]+1 = %p\n",a[0], a[0]+1);
printf("p[0] = %p,p[0]+1 = %p\n", p[0], p[0] + 1);
printf(" *a = %p, *a+1 = %p\n",*a, *a+1);
printf(" *p = %p, *p+1 = %p\n", *p, *p + 1);
printf("a[0][0] = %d\n", a[0][0]);
printf(" *a[0] = %d\n", *a[0]);
printf(" **a = %d\n", **a);
printf("a[2][1] = %d\n", a[2][1]);
printf("*(*(a+2)+1) = %d,\n",*(*(a+2)+1) );
return 0;
}
3.3 两数之和
题目:
给定一个整数组nums和一个目标target,请在该数组中找出和为目标值的那两个整数,并返回他们的数组下标。假设每个输入的数组只对应一个target,且数组中的同一个元素不能用两次。
示例:
给定nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回元素下标[0, 1]
// 两重循环解决-暴力解法
#include<stdio.h>
#include<stdlib.h>
int main()
{
int nums[] = { 2, 7, 11, 15 };
int target = 9;
int i, j;
int* ans = NULL;
for (i = 0; i < sizeof(nums) / sizeof(int); i++)
{
printf("%d\t", nums[i]);
}
putchar('\n');
for (i = 0; i < (sizeof(nums) / sizeof(int) - 1); i++)
{
for (j = i + 1; j < (sizeof(nums) / sizeof(int)); j++)
{
if (target == nums[i] + nums[j])
{
ans = (int*)malloc(sizeof(int) * 2);
ans[0] = i;
ans[1] = j;
}
}
}
for (i = 0; i < 2; i++)
{
printf("%d\t", ans[i]);
}
free(ans);
}
用函数对核心功能进行封装:
#include<stdio.h>
#include<stdlib.h>
int* twoSum(int* nums, int numsSize, int target, int* returnSize);
int main()
{
int nums[] = { 2, 7, 11, 15 };
int target = 9;
int i;
int* ans = NULL;
int returnSize = 0 ;
for (i = 0; i < sizeof(nums) / sizeof(int); i++)
{
printf("%d\t", nums[i]);
}
putchar('\n');
ans = twoSum(nums, sizeof(nums) / sizeof(int), target, &returnSize);
for (i = 0; i < returnSize; i++)
{
printf("%d\t", ans[i]);
}
free(ans);
}
int* twoSum(int* nums, int numsSize, int target, int* returnSize)
{
int i, j;
for (i = 0; i < numsSize - 1; i++)
{
for (j = i + 1; j < numsSize; j++)
{
if (target == (*(nums + i) + *(nums + j)))
{
int* ans = (int*)malloc(sizeof(int) * 2);
ans[0] = i, ans[1] = j;
*returnSize = 2;
return ans;
}
}
}
*returnSize = 0;
return NULL;
}
备注:在写for循环时,尽量不要有函数,如有函数,该函数会被执行多次。如:
int main(){
char s[]="dfafa";
for (int i=0; i<strlen(s); i++){ // strlen()函数利用循环求解字符串的长度,而for循环每次都会执行strlen(s)==>浪费时间
printf("%c", s[i]);
}
return 0;
}