IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C语言学习(五)——指针 -> 正文阅读

[C++知识库]C语言学习(五)——指针

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*)&num;
	short* p2 = (short*)&num;
	int* p3 = &num;
	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 &num;//返回值类型是指针(地址)类型
}


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;
}

?

?

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-02 13:24:33  更:2022-05-02 13:24:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/21 5:18:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码