指针
一.*的用法
int a = 10, b = 20;
int c = a * b;
int* p;//声明
int* p;
p = &a;//指向
*p = 100;//解引用
所谓指针,也就是内存的地址;所谓指针变量,也就是保存了内存地址的变量。指针的大小在32位平台是4个字节,在64位平台是8个字节,与类型无关
二.指针的值
《1》指针有两个值,一是自身的值(地址),二是所指之物的值(确切数值)
使用指针变量首先要明确指针变量自身的值(存储的是地址),再明确指针变量所指的实体(解引用)
三.指针有三种类型
1.普通指针;
2.空指针(int *p=nullptr; 指向为空);
3.野指针(int *p 对指针未进行初始化,只是声明,无指向能力)。
1)未被初始化,它的缺省值是随机的。
2)指针p被free或者delete之后,只是把指针所指的内存释放掉了,没有改变指针的值,此时,p沦落为野指针。
重点
void fun(int* p)
{
int a = 200;
*p = 100;
p = &a;
}
int main()
{
int x = 0;
int* s = &x;
fun(s);
printf("%d %d\n", x, *s);//100 100
return 0;
}
图解如下:
四.数组名的含义
数组名在sizeof中戴表整个数组,在其他情况下表示首地址
五.类型对指针的影响
<1>指针加一的能力受制于类型名
指针和整形相加减后任然是指针类型
<2>指针在解析中对内存的解析能力
六.指针的三种运算方法
<1>p取出来先与结合,结合之后指向下一地址。
<2>p取出来先与结合,结合之后本省再加一。
<3>p取出来先指向下一个地址,之后再和*结合。
七.数组和指针的关系
数组名在表达式中被自动转换为一个指向数组第一个元素的指针常量
C语言的下标运算符[ ]是以指针作为操作数的,ar[ i ],被编译系统解释为*(ar+i)。
1)数组名访问
2)指针访问
3)指针-指针运算
总结:两个同类型指针,指向连续空间可以相减,减后的结果是数据元素的大小;
当且仅当两个同类型指针变量指向同一数组中的元素时,可以用关系运算符>,==,!=等进行比较,比较规则是指向后边元素的指针高,指向同一元素的想等。
注意:两个指针不可相加
八.数组名的退化
用数组作为函数的形参,数组将退化为指针类型
指针在X86体系中开辟四个字节存放地址;
在X64体系中开辟八个字节存放地址;
九.指针变量与const
总结**:区分const是限制的指针变量还是指着变量指向的值:如果const位于的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果cons位于的右侧,const就是修饰指针本身,即指针本身是常量。**
十.无类型指针void*
void 不能定义变量,但可以定义指针变量。特别之处在于可以指向任一类型变量的地址如:
char ch='a';
int x=10;
double dx=12.23;
void *vp=&ch;
vp=&x;
vp=&dx;
如果要将void指针vp赋给其他类型的指针,则需要强制类型转换,如:
int *ip=(int*)vp; double *dp=(double*)vp;
void指针可以是任意类型变量的地址,函数中的形参为void*指针变量时,函数就可以接受任意类型变量的地址。
如:
void *memcpy(void*destination,const void *source,size_t num);
void *memset(void *ptr,int value,size_t num);
十一.指针补充
数组做形参退化为指针时,必须传递数组大小,可用以下三种方式声明,每种方式都会转成指针。
void Printf_Array(int br[],int n);
void Printf_Array(int br[5],int n);
void Printf_Array(int *br,int n);
退化为指针的根本原因:降低时间复杂度和空间复杂度
当形参为指针时,必须对指针进行判空且检查使用范围if(nillptr==br)return 0;
在模块函数中出现scanf_s时,需把需要的变量定义为形参
十二.二级指针
1.二级指针要义
int a = 10;
s=&p;
*s=&a;
**s=100;
s为二级指针,*s为一级指针,**s为变量本身的值;
s+1指向p1,加4个字节;只要是指针,只加(开辟)四个字节;
*s+1指向a1,sizeof(Type)*1个字节;//int 4;double 8;
**s+1为变量本身的值,值加一,不加字节。
2.二维数组与二级指针
(1)
s=&ar0;(数组地址)
*s=ar0;(数组首元素地址)
二维数组进行行优先存放,第一维可以缺省
(2)二维数组做形参,它将转化为指向一维数组的指针
附:
1.常见指针变量的定义
2.
1)冒泡排序
方法一:通过函数一一查找,牺牲时间换空间
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#define ArSize 100
int FindValue(const int* ar, int pos, int val)
{
if (nullptr == ar || n < 0)return;
while (pos>=0 && br[pos] != val);//while ( br[pos] != val&&pos = > 0)可做截断与
{
--pos;
}
return pos;
}
void Init_Ar(int* br, int n)
{
if (br == nullptr || n < 1)return 0;
for (int i = 0; i < n; i++)
{
br[i] = rand() % ARSIZE + 1;
}
while (i < n)
{
int temp = rand() % ARSIZE + 1;
int m = FindValue(br, i, temp)
if (m==-1)
{
br[i] == temp;
++i;
}
}
}
void BubbleSort(int* ar, int n)
{
if (nullptr == ar || n < 0)return;
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - i - 1; j++)
{
if (ar[j] > ar[j + 1])
{
int temp = ar[j];
ar[j] = ar[j + 1];
ar[j + 1] = temp;
}
}
}
}
void Printf(const int* ar, int n)
{
if (nullptr == ar || n < 0)return;
int i = 0;
for (int i = 0; i < ArSize; i++)
{
printf("%4d", ar[i]);
if ((i + 1) % 10 == 0)
{
printf("\n");
}
}
printf("\n");
}
int main()
{
int ar[ArSize] = {};
Init_Array(ar, ArSize);
Printf(ar, ArSize);
FindValue(ar, ArSize, 8);
Printf(ar, ArSize);
BubbleSort(ar, ArSize);
Printf(ar, ArSize);
return 0;
}
方法二:牺牲空间换时间
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#define ArSize 100
void Init_Array(int* ar, int n)
{
assert(*ar != NULL && n > 0);
int br[ArSize + 1] = {};
int i = 0;
while (i < n)
{
int tem = rand() % 100 + 1;
if (br[tem] == 0)
{
br[tem] = 1;
ar[i] = tem;
i++;
}
}
}
void BubbleSort(int* ar, int n)
{
if (nullptr == ar || n < 0)return;
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - i - 1; j++)
{
if (ar[j] > ar[j + 1])
{
int temp = ar[j];
ar[j] = ar[j + 1];
ar[j + 1] = temp;
}
}
}
}
void Printf(const int* ar, int n)
{
if (nullptr == ar || n < 0)return;
int i = 0;
for (int i = 0; i < ArSize; i++)
{
printf("%4d", ar[i]);
if ((i + 1) % 10 == 0)
{
printf("\n");
}
}
printf("\n");
}
int main()
{
int ar[ArSize] = {};
Init_Array(ar, ArSize);
Printf(ar, ArSize);
FindValue(ar, ArSize, 8);
Printf(ar, ArSize);
BubbleSort(ar, ArSize);
Printf(ar, ArSize);
return 0;
}
2)二分查找
int FindValue(int *ar,int n,int val)
{
assert(ar != NULL);
int pos = -1;
int left = 0, right = n - 1;
while (left <= right)
{
int mid = (right + left) / 2;
//int mid=(right-left)/2+left;
if (val < ar[mid])
{
right = mid - 1;
}
else if (val > ar[mid])
{
left = mid + 1;
}
else
{
int i = 0;
while(mid>=0&&val==ar[mid-1])
{
mid--;
}
pos = mid;
break;
//if(mid>left&&ar[mid-1]!=val){
//pos = mid;
//break}
//right = mid - 1;
}
}
return pos;
}
int main()
{
int ar[] = { 12,12,12,12,12,12,12,23,34,45,56,67,78,89,100 };
int n = sizeof(ar) / sizeof(ar[0]);
for (int i = 0; i < n; i++)
{
printf("%d=>%d\n", ar[i], FindValue(ar,n,ar[i]));
}
return 0;
}
3)循环移动数组
一.时间复杂度(k*n)
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
void Printf_Ar(const int* br, int n)
{
assert(br != nullptr);//Debug
for (int i = 0; i < n; i++)
{
printf("%d ", br[i]);
}
printf("\n");
}
void Right_Move_Array(int* br, int n)
{
assert(br != NULL || n > 0);
int tem = br[n - 1];
for (int i = n - 1; i > 0; i--)
{
br[i] = br[i - 1];
}
br[0] = tem;
}
void Left_Move_Array(int* br, int n)
{
assert(br != NULL || n > 0);
int tem = br[0];
for (int i = 0; i < n - 1; i++)
{
br[i] = br[i + 1];
}
br[n-1] = tem;
}
void Left_Move_Array_k(int* br, int n, int k)
{
assert(br != NULL || n > 0);
if (k >= 0)
{
k = k % n;
for (int i = 0; i < k; i++)
{
Left_Move_Array(br, n);
}
}
else
{
k = -k;
k = k % n;
for (int i = 0; i < k; i++)
{
Right_Move_Array(br, n);
}
}
}
void Right_Move_Array_k(int* br, int n, int k)
{
Left_Move_Array_k(br, n, -k);
}
//断言只在Debug模式下起作用
//release是一种优化模式,会直接删掉错误语句
//如果在调试过程中会出现一些无法预料的错误,则使用if机制
int main()
{
const int n = 10;
int ar[n] = { 12,23,34,45,56,67,78,89,100};
Printf_Ar(ar, n);
Right_Move_Array(ar, n);
Printf_Ar(ar, n);
Left_Move_Array(ar, n);
Printf_Ar(ar, n);
Left_Move_Array_k(ar, n, 4);
Printf_Ar(ar, n);
Right_Move_Array_k(ar, n, 4);
Printf_Ar(ar, n);
}
二.时间复杂度(n)
```cpp
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#define ArSize 10
void ResArray(int* br, int left, int right)
{
assert(br != NULL && left < right);
while (left < right)
{
int temp = br[left];
br[left] = br[right];
br[right] = temp;
right--;
left++;
}
}
void Left_Move_Array_K(int* br, int n, int k)
{
assert(br != nullptr && n > 0);
k = k % n;
ResArray(br, 0, k - 1);
ResArray(br, k, n - 1);
ResArray(br, 0, n - 1);
}
void Print_f(int* br, int n)
{
assert(br != NULL && n > 0);
for (int i = 0; i < n; i++)
{
printf("%d ", br[i]);
if ((i + 1) % 10 == 0)
{
printf("\n");
}
}
}
int main()
{
int ar[ArSize] = {0,12,23,34,45,56,67,78,89,100};
Print_f(ar,ArSize);
Left_Move_Array_K(ar, ArSize, 3);
Print_f(ar, ArSize);
return 0;
}
三.时间复杂度(1)
结构体移动
struct MyArray
{
int data[ArSize];
int maxsize;
int curpos;
};
void Right_Move_K(struct MyArray* br, int k);
void Left_Move_K(struct MyArray* br, int k);
void Left_Move_K(struct MyArray* br, int k)
{
assert(br != NULL);
if (k < 0)
{
Left_Move_K(br,-k);
}
else
{
int i = br->curpos;
i += k;
i = i % 10;
br->curpos = i;
}
}
void Right_Move_K(struct MyArray* br, int k)
{
assert(br != NULL);
if (k < 0)
{
Right_Move_K(br,-k);
}
else
{
int i = br->curpos;
i -= k;
if (i >= 0)
{
br->curpos = i;
}
else
{
br->curpos = br->maxsize + i;
}
}
}
int GetElem(struct MyArray* br, int index)
{
assert(br != NULL);
int i = br->curpos;
i += index;
i = i % 10;
return br->data[i];
}
void Printf(struct MyArray* br)
{
assert(br != NULL);
for (int i = 0; i < ArSize; i++)
{
printf("%d ", GetElem(br, i));
}
printf("\n");
}
int main()
{
struct MyArray ar;
ar.maxsize = 10;
ar.curpos = 0;
for (int i = 0; i < ar.maxsize; i++)
{
ar.data[i] = i + 10;
}
Printf(&ar);
//for (int i = 0; i < ArSize; i++)
//{
// printf("%d ", GetElem(ar, i));
//}
Right_Move_K(&ar, 2);
Printf(&ar);
Left_Move_K(&ar, 2);
Printf(&ar);
return 0;
}