1.指针的算术运算
(1)指针之间不允许相加,但允许相减
指针相减表示两个指针之间间隔的单元格数(1.先计算出字节数 2.再除以权重)
(2)指针运算需要调整
p+数字(n) 加n单元格的权重 权重为指针变量去掉一个*,求sizeof(),乘n
数字之间不需要调整,直接加或减
#include <stdio.h>
#include <stdlib.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9};
int *p = arr; //指针-指针
int *q = &arr[8];
printf("%d\n",p-q);//-8
printf("%d\n",q-p);//8
printf("%d\n",(short *)q-(short *)p);//16
printf("%d\n",(double *)q-(double *)p);//4
printf("%d\n",(unsigned long)q-(unsigned long)p);//32
int *p1 = (int *)2000;//指针+-数字
printf("%d\n",p1+2);//2008
printf("%d\n",(char *)p1+2);//2002
printf("%d\n",(long long)p1+2);//2002
printf("%d\n",(double **p1+2);//2008
}
2.数组和指针的替换
int arr[10];
int *p = arr;
arr[i] = *(arr+i);
p[i] = *(p+i);
3.指针和数组的其他知识
(1)数组名代表整个数组长度的两种情况
int arr[10] = {0,1,2,3,4,5,6,7,8,9};
sizeof(arr) = 40;
cout<<&arr<<endl;//1000
cout<<&arr+1<<endl;//1040
(2)类型
int arr[10]; int *p = arr;
int brr[3][4]; int (*q)[4] = brr;//二维数组的数组名是指向一位数组的指针
brr[0]是int*类型
brr[0]+1是int*类型(+数字,对类型无影响)
brr[2][3]是int类型
(3)二位数组是否越界
int brr[3][4] = {{1,2,3},{4,5,6},{7}};
printf("%d\n",brr[0][6]);//6 二维数组是线性存储的,可以越界访问
(4)字符串的定义正确的是?
char str1[5] = {'a','b','c'};//ok
char str2[5] = {"abc"};//ok
char str3[5] = "abc";//ok
char str4[] = "hello"; //ok
char str5[5] = "hello";//error,越界
(5)字符数组的大小
sizeof—求内存的字节数,所有的字符都要放进去
strlen—字符串的有效长度,碰到’\0’就结束
#include <stdio.h>
int main()
{
char str1[100] = "abcde";
char str2[100] = "abcd\0ef\n";
char *str3 = "abcde";
char *str4 = "abcd\0ef\n";
char str5[] = "abcde";
char str6[] = "abcd\0ef\n";
printf("%d,%d\n",sizeof(str1),strlen(str1));//100,5
printf("%d,%d\n",sizeof(str2),strlen(str2));//100,4
printf("%d,%d\n",sizeof(str3),strlen(str3));//4,5
printf("%d,%d\n",sizeof(str4),strlen(str4));//4,4
printf("%d,%d\n",sizeof(str5),strlen(str5));//6,5
printf("%d,%d\n",sizeof(str6,strlen(str6);//9,4
return 0;
}
(6)字符数组和字符串常量的区别
int main()
{
char *str1 = "abcde";//1
char str2[] = "abcde";//2
str1[0] = 'x';//3 编译没问题,运行崩溃
str2[0] = 'x';//4
return 0;
}
str1是字符常量,在全局静态变量区(.rodata段),不能修改其值
str2是字符数组,在栈上,自己的内存,可以随便修改
改错题可能会考,需要在定义时显示的加上const,这样编译就不会通过
const const char *str1 = “abcde”;
(7)下列各变量的含义
int *a;//整型指针
int *b();//函数,无参数,返回值是int *
int c[4];//整型数组
int *d[4];//指针数组,每个数组的元素是一个int类型的指针
int (*e)[4];//数组指针,该指针指向一个含有4个整型元素的数组
int (*f)();//函数指针,该指针指向一个函数,函数无参数,返回值是int类型
4.交换函数
#include <stdio.h>
void Swap1(int *p1, int *p2)
{
int *tmp = p1;
p1 = p2;
p2 = tmp;
}
void Swap2(int *p1, int *p2)
{
int *tmp;//野指针
*tmp = *p1;
*p1 = *p2;
*p2 = *tmp;
}
void Swap3(int *p1, int *p2)
{
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
int main()
{
int a = 10;
int b = 20;
printf("a=%d,b=%d\n",a,b);
Swap1(&a, &b);
printf("swap1:a=%d,b=%d\n",a,b);
Swap2(&a, &b);
printf("swap2:a=%d,b=%d\n",a,b);
Swap3(&a, &b);
printf("swap3:a=%d,b=%d\n",a,b);
return 0;
}
子函数和父函数之间要建立联系,必须传指针并解引用
5.返回数组/指针
#include <stdio.h>
char *Fun1()
{
char arr[] = "hello world";
return arr;
}
int main()
{
printf("%s\n",Fun1());///返回局部数组,乱码
}`
arr是局部变量,出Fun1函数后,函数栈帧回退,arr的地址可能已经被重新分配给别的函数使用。不能返回局部变量!!!
6.结构体和联合体
struct A
{
char a;//1+1
short b;//2
int c;//4
};//8
struct B
{
char a;//1+3
int b;//4
short c;//2
};//10+2
struct C//位段
{
int a:10;//a占10位
int b:2;//a占2位
};//4,必须是int的倍数
struct D
{
char a;//1
struct DD//有类型有变量,以单个最大的数据类型对齐
{
char b;//1+3
int c;//4
}d;//8
};//9+3
struct E
{
short a;//2
struct EE//有类型没变量,不占内存
{
char b;
int c;
};//不占内存
int d;//4
};//6+2
struct F
{
int a;//4
struct//没类型没变量,生成一个透明的变量,a/b/c/d同级
{
char b;//1+3
float c;//4
};
char d;//1+3
};//16
struct G
{
char a;//1
struct//只有变量没有类型(与有变量有类型)相同
{
char b;//1+3
int c;//4
}d;//8
};//9+3
union H//共用体
{
char a;
short b;
int c;
};//4
7.可变参数编程 3个宏
需要引入头文件#include<stdarg.h>
va_list list;//相当于char* list;
va_start(list, num);//找到...开头
va_arg(list,int);//从…取数据
va_end(list);//list==NULL,关闭
编程题:编写一个名叫max_list的函数,它用于检查任意数目的整型参数并返回它们中的做大值,参数列表必须以一个负数结尾,提示列表的结束。
#include <iostream>
#include <stdarg.h>
using namespace std;
int Max_list(int a,...)//1,4,9,-1
{
int max = a;
int cur = a;
va_list list;//char *list;
va_start(list,a);//找到...开头
while(cur >= 0)
{
cur = va_arg(list,int);//从...取数据
if(max < cur)
{
max = cur;
}
}
va_end(list);//list = NULL;
return max;
}
int main()
{
printf("%d\n",Max_list(1,5,9,0,2,5,-1));
return 0;
}
8.malloc常见错误
malloc一般都是内存的问题(程序崩溃/内存泄露)
面试题:C++是兼容C的,C已经有了malloc/free,C++为什么还要有new/delete?
答:malloc/free是C语言的标准库函数,new/delete是C++的运算符
对于非内置数据类型的对象来说,使用malloc/free无法满足动态创建对象的要求。对象创建的时候要自动调用构造函数,对象消亡的时候要自动调用析构函数。malloc/free是库函数,不在编译器权限的控制范围内,不能把调用构造函数和析构函数的任务强加给malloc/free。因此,C++需要一个能完成动态分配并初始化内存的运算符new,一个可以清理并释放内存的运算符delete。