Ps:相信学过C语言的同学都知道,指针是C语言中最重要也是最难攻克的部分,下面的代码中的注释部分请同学们要仔细阅读
一、指针&指针变量
?
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<stdlib.h>
//32位编译器(0x0000 0000-0xffff ffff):
//指针变量:
//存放指针(地址)的变量
//因为地址编号(0x0000 0000)如此,所以我们指针变量占4个字节就可以存下
//64位编译器(0x0000 0000 0000 0000-0xffff ffff ffff ffff):
//指针变量占8个字节
//指针变量的定义和初始化
//指针变量的定义:
int main01()
{
using namespace std;
int a = 10;
定义指针的步骤:
1.*与符号结合代表是一个指针变量
2.要保存谁的地址,将他的定义形式放在此处
3.用*p替换掉定义的变量
定义指针变量的格式:
数据类型 * 变量名
!!注意!!指针变量的类型是 数据类型*(例:int *p的指针变量类型是int*,p是变量!!)
int* p;
分析
与*结合代表这是一个指针变量
p是变量,p的类型是将变量p本身拖黑,剩下的类型就是指针变量的类型
指针变量p用来保存什么类型数据的地址,将指针变量p和指针变量p最近的*一起拖黑,
//剩下什么类型就保存什么类型数据的地址
p = &a;
int* i_porint = &a;
system("pause");
return (0);
}
//指针的使用
//指针变量保存了谁的地址就指向了谁
int main02()
{
//在使用(最常见是赋值时,因为等号两边数据类型要匹配)时,对一个表达式取*,就会对表达式减一级*,如果对表达式取&,就会加一级*
using namespace std;
int a = 10;
int* p = &a;
*p = 100;//在使用时,*与p结合代表,取p指针所指向的那块空间的内容
cout << *p << endl;//*p: p指向地址中的内容
cout << p << endl;//p: p指向的地址空间
cout << a << endl;
//注意!!!&可以取得一个变量在内存中的地址,但是,不能取寄存器变量,因为寄存器变量不在内存里,而在CPU里面,所以是没有地址的
system("pause");
return (0);
}
//指针变量的大小sizeof()
//不管什么类型的指针,大小只和系统或编译器的位数有关
int main03()
{
using namespace std;
char* p1;
short* p2;
int* p3;
int** p4;
cout << sizeof(p1) << endl;
cout << sizeof(p2) << endl;
cout << sizeof(p3) << endl;
cout << sizeof(p4) << endl;
system("pause");
return (0);
}
//指针的宽度和步长 宽度也可以理解成步长
int main04()
{
using namespace std;
int num = 0x01020304;
char* p1 = (char*)#
short* p2 = (short*)#
int* p3 = #
int** p4;
printf("%x\n", *p1);//4
printf("%x\n", *p2);//304
printf("%x\n", *p3);//01020304
//通过*取指针指针变量所指向的那块空间内容时,取的内存的宽度和指针变量本身的类型有关
//指针的宽度(步长)=sizeof(将指针变量与指针变量最近的*拖黑,剩下的类型)
//步长:指针+1跨过的字节数
printf("%p\n", p1);
printf("%p\n", p2);
printf("%p\n", p3);
printf("%p\n", p1 + 1);
printf("%p\n", p2 + 1);
printf("%p\n", p3 + 1);
system("pause");
return (0);
}
//野指针
int main05()
{
using namespace std;
int* p;
//*p=200;
//printf("%d\n",*p)
//野指针:就是没有初始化的指针,指针的指向时随机的不可以操作野指针
//指针变量保存的地址一定是定义过的(向系统申请过)
system("pause");
return (0);
}
//空指针
int main06()
{
using namespace std;
int a;
//将指针的值赋值给0,0x00000000 = NULL
int* p = NULL;//给指针p的内容赋值为0
if (p != NULL)
{
p = &a;
}
*p = 200;//错误 因为p保存了0x0000的地址,这个地址是不可以被赋值的
printf("%d\n", *p);
system("pause");
return (0);
}
//万能指针
int main07()
{
using namespace std;
//void b; 不可以定义void类型的变量,因为编译器不知道给变量分配多大的空间
//但是可以定义void*类型,因为指针都是4个字节
int a = 10;
short b = 20;
void* q = (void*)&b;
void* p = (void*)&a;//万能指针可以保存任意的地址,在不知道所指向变量的数据类型时,
//需要强制转换数据类型(为了保持赋值=两边数据类型匹配)
printf("%d\n", *(int *)p);//*((int *)地址)
system("pause");
return (0);
}
//const修饰的指针
int main08()
{
using namespace std;
const int a = 10;//修饰变量a,不能再通过a修改a内存里面的内容
/* int *p;
p = &a;
*p = 100;*/
system("pause");
return (0);
}
int main09()
{
using namespace std;
const int* p;//const在这里修饰的是*
int a = 10;
p = &a;//不能通过*p,改p所指向空间的内容
//*p = 100;err 因为不能通过p改p所指向的内容
//const修饰的指针变量p
//p保存的地址不可以被修改,不能通过*p修改p所指向的那块空间的内容
int* const p = &a;
//p=&b;err p本身的值不能被改变
//不想被改变的数据,就用const修饰即可
system("pause");
return (0);
}
?
二、多级指针&数组与指针
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<stdlib.h>
//1.多级指针
int main10()
{
using namespace std;
int a = 10;
int* p = &a;
//现在需要定义一个指针去指向指针变量p所在的地址
//p的数据类型是int*, 用新指针*q代替指针变量p, 数据类型是int*
int** q = &p;
//*q代表指针变量p中的内容--变量a的地址
//**q代表的是a的值
//**q==*(*q)==*(&a)==*(p)==a
//如果*和&相遇则抵消
int*** k = &q;
//*与符号结合,代表这个k是一个指针变量
//k是一个变量
//k的类型,将变量k拖黑,整下的类型
//k用来保存谁的地址,将变量k和k最近的*一起拖黑,剩下什么类型就保存什么类型数据的地址
system("pause");
return (0);
}
//2.数组与指针
//通过指针操作数组元素
int main11()
{
using namespace std;
int a[10] = { 1,2,3,4,5,6,7,8,9,10 };
int b[10] = { 0 };
//a 数组名,首元素的地址
int* p = a;//指针p保存的是首元素的地址
for (int i = 0; i <sizeof(a)/sizeof(a[0]); i++)
{
cout << a[i] << " ";
}
cout << endl;
for (int j=0; j < sizeof(a) / sizeof(a[0]); j++)
{
cout << *(p + j) << " ";
}
cout << endl;
for (int z = 0; z < sizeof(a) / sizeof(a[0]); z++)
{
*(p + z) = z;
cout << *(p + z) << " ";
}
cout << endl;
system("pause");
return (0);
}
//指针的运算
int main()
{
using namespace std;
int a[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* p = a;//指针变量p指向数组a首元素地址
int* q = (int*)(&a + 1) - 1;//&a的步长是整个数组,&a+1直接跨过数组a,
//(int*):强制转化为指针类型,步长为四字节,(int*)(&a + 1) - 1 == int *q = &a[9];
//或者:int *q = &a[9];
cout << q - p << endl;//输出的是数组a的元素个数,
cout << *(p + 3) << endl;//a[3]的值
//在c语言中,两个指针相加,没有意义!!!!
//两指针相减(类型一致),得到的是中间跨过多少元素
system("pause");
return (0);
}
//[]不是数组的专属
int main13()
{
using namespace std;
int a = 10;
int* p = &a;
p[0] = 100;
cout << "a=" << a << endl;//输出结果为a = 100
//原因是,[]==*()
//p[0] == *(p+0);
int b[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* q = b;
for (int i = 0; i < sizeof(b) / sizeof(b[0]); i++)
{
cout << b[i] << endl;
cout << *(q + i) << endl;
cout << q[i] << endl;
//三者结果相同
}
system("pause");
return (0);
}
//3.指针数组
//整形数组:是一个数组,数组中的每一个元素都是整形
//指针数组:是一个数组,数组中的每一个元素都是指针
int main14()
{
using namespace std;
int a = 10;
int b = 20;
int c = 30;
//int *p1 = &a int *p2 = &b int *p3 = &c;
//需求: 数组中的每一个元素都是指针(地址)
int* num[3] = { &a,&b,&c };//定义了一个指针数组,并且初始化
//数组类型:int * [3]
cout << sizeof(num) << endl;//数组的长度
cout << *num[0] << endl;//a的值
for (int i = 0; i < sizeof(num) / sizeof(num[0]); i++)
{
cout << *num[i] << " ";
}
cout << endl;
int** p = num;
cout << **p << endl;
for (int j = 0; j < sizeof(num) / sizeof(num[0]); j++)
{
cout << **(p + j) << " ";
}
cout << endl;
system("pause");
return (0);
}
?
?三、指针与函数
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<stdlib.h>
//1.指针与函数
//指针作为形参
int main15()
{
using namespace std;
void swap(int*, int*);
int a = 10;
int b = 20;
int* p1 = &a;
int* p2 = &b;
swap(p1, p2);
cout << "a= " << a << endl;
cout << "b= " << b << endl;
system("pause");
return (0);
}
void swap(int* a, int* b)
{
int temp;
temp = (*a);
(*a) = (*b);
(*b) = temp;
return;
}
int main16()
{
using namespace std;
int a[10] = { 1,2,3,4,5,6,7,8,9,10 };
return 0;
}
?(续)
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
using namespace std;
int num = 0;//在函数外面定义的变量是全局变量,整个工程都可以使用
//这个变量程序启动开辟空间,知道程序结束时才释放空间
void print_arr(int b[10])//数组做形参,系统会自动转化为指针 int *b;
{
for (int i = 0; i < sizeof(b) / sizeof(b[0]); i++)
{
cout << b[i] << " ";
}
cout << endl;
cout << sizeof(b) << endl;//打印结果为:4 说明数组做形参,就会退化为指针
cout << sizeof(b[0]) << endl;//打印结果为:4 所以sizeof(b) / sizeof(b[0])==1,因此只会打印一个字节
}
void out_arr(int *b,int n)//n代表数组中的元素个数
{
for (int i = 0; i < n; i++)
{
cout << *(b+i) << " ";
}
cout << endl;
}
//1.数组名作为函数的参数
int main01()
{
int a[10] = { 1,2,3,4,5,6,7,8,9,10 };
print_arr(a);//打印数组内容
//没有输出整个数组的值,只打印了第一个元素的值
out_arr(a, sizeof(a) / sizeof(a[0]));
system("pause");
return 0;
}
//2.指针作为函数的返回值
int* getnum()//函数的类型要与函数返回值的类型相同
{
//函数{}中定义的变量是局部变量,局部变量在函数结束后的空间会被释放
srand(time(NULL));
num = rand();
return #//返回值类型是指针(地址)类型
}
int main02()
{
int* p = getnum();
cout << *p << endl;
system("pause");
return 0;
}
四、指针与字符数组
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
using namespace std;
//1.指针与字符数组
int main05()
{
char a[] = "helloworld";//定义了一个字符数组,字符数组内容为helloworld\0
//定义一个指针用来保存数组首元素的地址
char* p = a;
printf("%s\n", p);//打印一个字符串,要的是首个字符的地址
printf("%s\n", p + 2);
printf("%c\n", *(p+3));
printf("%d\n", sizeof(a));//11
printf("%d\n", sizeof(p));//4
printf("%d\n", strlen(a));//10
printf("%d\n", strlen(p));//10
p++;
printf("%s\n", p);//输出elloworld;
//指针指向那个元素,打印时就从那个元素开始打印
system("pause");
return 0;
}
int main06()
{
char a[] = "helloworld";
char* p = a;
//p = "abcdef";//字符常量存文字常量区,p中存的是字符串首元素地址,“”在使用时,取的是字符串首元素的地址
system("pause");
return 0;
}
//字符指针作为形参
char * my_strcat(char* scr, char* dst)
{
int n = strlen(scr);
int i = 0;
while (i = strlen(dst))
{
scr[n + i] = dst[i];
i++;
}
scr[i + 1] = 0;
return scr;
}
int main07()
{
char str1[128] = "hello";
char str2[128] = "123456";
char* my_strcat(char*, char*);
//将str2拷贝到str1后面
//字符数组作为形参时,不用告知数组中元素的个数,因为字符数组中最后会有结束符'\0',判断什么时候出现结束符就可以了
;
cout << my_strcat(str1, str2) << endl;
system("pause");
return 0;
}
//字符指针数组
//是一个数组,每一个元素时字符指针
int main08()
{
int* arr[10];
/*char* p1 = "heihei";
char* p2 = "haha";
char* p3 = "xixi";
char* num[3] = { p1,p2,p3 };*/
//char* arr[3] = { "heihei","haha","xixi" };//把三个字符串常量的首地址存在数组里面
for (int i = 0; i < 3; i++)
{
cout << arr[i] << endl;//输出了三个字符串常量
}
cout << *arr[0] << endl;//输出结果为h;
cout << *(arr[1] + 1) << endl;//输出结果为a
system("pause");
return 0;
}
//字符指针数组作为main函数参数
//.exe
//在没有给文件命令参数时,argc中保存的是1 argv中保存的是。exe文件的路径
//点击项目名称,右击选择属性-->调试-->命令参数处可以为main函数传参,各个参数的首地址存放在argv数组中
//char* argv[] = {".*.exe","hello","123456"};
//argc是执行可执行程序的参数个数
//argv是一个字符指针数组,保存的是参数(字符串)的首元素地址
int main(int argc, char* argv[])
{
cout << argc << endl;
cout << argv[0] << endl;
cout << argv[1] << endl;
cout << argv[2] << endl;
cout << argv[3] << endl;
system("pause");
return 0;
}
五、指针练习
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
using namespace std;
//1.找出数组中第二大的数,(使用*操作数组元素个数,不要使用[])
int main03()
{
int a[] = { 100,100,100,234,123,500,32,68,41,99,13,71 };
int* p = a;
int* q = (int*)(&a + 1) - 1;
int temp = 0;
for (int i = 0; i < (q - p); i++)
{
for (int j = 0; j < (q - p) - i ; j++)
{
if (*(p + j) > *(p + j + 1))
{
temp = *(p + j);
*(p + j) = *(p + j + 1);
*(p + j + 1) = temp;
}
}
}
cout << *(q-1) << endl;
cout << q-p << endl;
system("pause");
return 0;
}
//不使用库函数,实现字符串拷贝功能
//char src[100] = "hello";
//char dst[100]; //把src的内容拷贝给dst
//函数名:void my_strcpy(char dst[],char src[]);
int main04()
{
char src[100] = "hello";
char dst[100] = {0};
char* p = src;
char* q = dst;
int i = 0;
for (i = 0; *(p + i) != '\0'; i++)
{
*(q + i) = *(p + i);
//dst[i] = src[i];
//q[i] = p[i];
//*(dst+i) = *(src+i);
//四者等价
}
*(q + i + 1) = '\0';//补结束符
cout << "src= " << src << endl;
cout << "dst= " << dst << endl;
system("pause");
return 0;
}
?
?
|