文章目录
数组
数组的类型有元素类型和数量决定
数组大小不能用变量定义,只能是一个正整数常量
数组作为函数的形参传递时会退化为指针
数组名代表数组的首地址 a == &a[0]
二维数组
- 类型名 数组名 [ 行 ] [ 列 ];
- 二维数组本质上由多个一维数组构成。
int ar[3] [4]:由三个一维数组构成,每个一维数组的大小是4个整型元素
对二维数组初始化时,一维长度可以缺省,二维的长度不可缺省
指向数组的指针
-
int *p[10]:指针数组 首先是个数组 数组中有10个元素 每个元素都是指针
-
int (*p)[10] :行指针 指针变量 含有10个元素的一维数组
例题1:一个二维数组的行和列的元素交换
int main()
{
int ar[2][3] = { 1,2,3,4,5,6 };
int br[3][2] = { 0 };
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
br[j][i] = ar[i][j];
}
}
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 2; j++)
{
cout << br[i][j] << " ";
}
cout << endl;
}
return 0;
}
杨辉三角
例题2:杨辉三角
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
int ar[10][10]; //使用二维数组实现
for (int i = 0; i <= 10; i++)
{
for (int j = 0; j <= i; j++)
{
if (i == j || j == 0)
{
ar[i][j] = 1;
}
else
{
ar[i][j] = ar[i - 1][j] + ar[i - 1][j - 1];
}
}
}
int ar[10]; //使用一维数组实现
for (int i = 0; i <= 10; i++)
{
ar[i] = 1;
for (int j = i - 1; j > 0; j--)
{
ar[j] = ar[j] + ar[j - 1];//某一行中间的数等于上一行对应位置数字之和
}
for (int j = 0; j <= i; j++)
{
cout << ar[j] << "\t";
}
cout << endl;
}
柔性数组
柔性数组:数组大小声明为0,或不给出大小称为柔性数组。
- 柔性数组不占用存储空间
一页的大小是4k
struct sd node
{
int num;
int size;
char data[]; // 只能有一个结构体的最后一个元素是数组
}; //数组开辟的特点:大开小用
sizeof(struct sd node) = 8; //柔性数组不占用存储空间
struct kd_node //8
{
int num;
int size;
char data[];//data[0]
};
int main()
{
struct kd_node* p1 = (struct kd_node*)malloc(sizeof(struct kd_node)+20);
if(nullptr == p1)
{
exit(EXIT_FAILURE);
}
strcpy(p1->data,20,"yhping");
p1->num = strlen("yhping");
p1->size = 20;
free(p1);
p1 = nullptr;
return 0;
}
一次性给出28字节
int main()
{
struct kd_node s1 = {6,7,"yhping"};
struct kd_node s2 = {11,12,"yhpinghello"};
}
//sizeof(s1) => 8 编译时确定大小
//sizeof(s2) => 8
struct kd_buff //12
{
int num;
int size;
char* buff;
}
kd_buff* p = (kd_buff*)malloc(sizeof(kd_buff));
p->num = 6;
p->size = 7;
p->buff = (char*)malloc(sizeof(char) * 7);
strcpy_s(p->buff, 7, "yhping");
free(p);free(p->buff);
指针
定义
- 计算机中所有的数据都必须存放在内存中,不同类型的数据占用的字节数不一样。为了正确访问数据,必须为每个字节编上号码,将内存中字节的编号称为地址或指针。地址从0开始以此增加。
- 在指针变量定义中, * 与变量名结合
- 指针的大小在32位是4个字节,64位是8个字节
- 指针变量自身的值存储的是地址,指针变量所指的实体(解引用)
- 定义指针变量时,类型对指针变量起到两个作用:
1)解析存储单元的大小
2)指针变量加1的能力 int 加1 加四个字节 - 使用指针变量之前一定要进行初始化,防止野指针
- 指针类型不同,不能相互赋值,必须进行强制类型转换
- 的意义
int c = a* b; 乘号
int * p = &a; 指针变量,
*p = 100; 解引用,获取指针指向的数据,间接操作
int a = 10, b = 20;
int* pa = &a;
int* pb = &b;
if (*pa > *pb) { cout << 1 << endl; } // 比较的是指针指向的数据 10 20
else cout << 2 << endl;
if (pa > pb) { cout << 3 << endl; } // 比较的是指针的地址
else cout << 4 << endl;
- 值传递、指针传递
void Swap(int a, int b) //值传递
{
int c = a;
a = b;
b = c;}
void Swap_r(int* a, int* b) //指针传递 地址
{
int c = *a;
*a = *b;
*b = c;}
int main()
{ int x = 10, y = 20;
Swap(x, y);
cout << x << " " << y << endl; //10 20
Swap_r(&x, &y);
cout << x << " " << y << endl; //20 10
void fun(int* p)
{
int a = 200;
*p = 100;
p = &a;
}
int main()
{
int x = 0;
int* s = &x;
fun(s);
cout << x << "\t" << *s << endl; //100 100
指针参数是如何传递内存的
如果函数的参数是指针的话,不能指望这个指针去申请动态内存。
原因:编译器为每个函数的参数分配了临时副本,指针参数p的副本是_p,编译器是_p=p;分配内存时,为_p分配了内存,但是指针p却没有指向这块内存,所以函数不会分配到内存
解决:定义时或传参前要进行动态内存的申请
void GetMemory(char** p, int num)
{
*p = (char*)malloc(sizeof(char) * num);
}
int main()
{
char* str = NULL;
GetMemory(&str, 100);
strcpy_s(str, 5, "hello4444");
cout << str << endl;
free(str);
str = NULL;
return 0;
}
指针的运算
注:指针的运算很容易超出数组边界,注意越界问题
- 类型加1 加sizeof(int)个字节
const int n = 5;
int ar[] = { 12,23,34,45,56 };
int* ip = &ar[0];
for (int i = 0; i < n; i++)
{
cout << ip << "->" << *ip<< endl;
ip += 1; //int类型 ip+1 加四个字节
}
-
指针和整型加减后的结果仍然是指针类型
指针与整型量i的加减等于指针值(地址)与i*sizeof(目标类型)积的加减,得到新的地址 -
指针 - 指针
1)两个同类型指针,只想连续空间可以相减,减后结果是数据元素大小
int类型指针-int类型指针 是整型元素个数
2) 当且仅当两个同类型指针变量指向同一数组中的元素时,可以用关系运算符>,==,!=进行比较。比较规则是指向后面元素的指针高,指向同一元素的相等
const和指针
const与指针搭配可以限制指针变量;限制指针变量指向的数据
- 限制指针变量本身 int * const p;
指针变量本身的值不能被修改,指向可以改变,所以const修饰的指针变量只能在定义时初始化,不能定义之后在赋值
int * const ip = &a; //定义时就要初始化
*ip = 200; //ok
ip = &b; //err
- 限制指针变量指向的数据 const int * ip; int const * ip;
指针可以指向不同的变量,但不能使用指针修改指针指向数据的值
int const * ip = NULL;
ip = &b; //ok
ip = &a; //ok
*ip = 100; //err
- 限制指针变量和指针变量指向数据的值 const int * const ip;
指针本身不能改变并且指针的指向也不能改变
const int * const ip = &a;
//第一个修饰指向
//第二个修饰指针本身
注:
const修饰的内容不能作为左值
不能泄露常量的地址给非常量的指针
const修饰的类型是离他最近的第一个成型的指针、其余全是它修饰的内容
如果const修饰的内容不包含指针,则无法参与类型
* 和 &
int a=10;
int * ap = &a;
1)*&a: * (&a),&a表示取变量a的地址, *(&a)表示取地址里面的数据,等价于a
2)& ap:& ( * ap), * ap表示ap地址里面的数据,& ( * ap)表示数据的地址,等价于ap(a的地址)
3) * &ap: (&ap),&ap表示取变量ap的地址, *(&ap)表示取地址里面的数据,等价于&a(ap地址里面的数据存放的是a的地址 &a)
无类型指针 void* 泛型指针
void不能定义变量,但可以定义指针变量,void指针可以指向任意类型变量的地址
void指针变量称为泛型指针,是指针都可以给void指针变量赋值
如果将void指针赋给其他类型的指针,则需要强制类型转换
int a =0; char ch = 'x';
void* vp = &ch;
vp = &a;
int *ip = (int *)vp;
二级指针
如果一个指针指向的是另外一个指针,就称为二级指针(指向指针的指针)
指针与数组
指针与数组的关系
数组名在表达式中被自动转换为一个指向数组第一个元素的指针变量
ar表示数组第一个元素的地址 * ar表示数组第一个元素 ar[0]
ar+1表示数组第二个元素的地址, *(ar+1)表示数组第二个元素ar[1]
*ar[i]被编译系统解释为 (ar+i)
指针与数组的对比
数组在静态存储区或者栈上被创建,数组名对应一块内存,其地址和容量在生命周期内保持不变,只有数组的内容可以改变。
指针可以随时指向任意类型的内存块,可以随时改变的,指针比数组更加灵活
指针与数组的区别
- 修改内容
char a[] = "hello";
a[0]='x';
cout<<a<<endl;
char* p = "hello"; //编译器给出错误
//const char* 不能初始化char *;“hello”是常量,
p[0] = 'x'; //不能通过P[0]='x'修改内容
- 内容复制与比较
- 计算内存容量
数组给指针赋值
int main()
{
char ar[] = "leelle";
char* br = (char*)malloc(sizeof(char)*(strlen(ar)+1));
if (NULL == br)
{
cout << "br malloc err\n" << endl;
return 0;
}
strcpy_s(br, sizeof(ar),ar);
cout << br << endl;
free(br);
br = NULL;
return 0;
}