指针引用多维数组
#include<stdio.h>
void main() {
int a[3][4] = {
{1,2,3,4},
{5,6,7,8},
{9,10,11,12}
};
//二维数组名,指向一维数组a[0],即0行首地址
printf("%p\n", a);
//0行0列元素地址
printf("%p\n", a[0]);
printf("%p\n", *a);
//1行首地址
printf("%p\n", a+1);
//1行0列元素的地址
printf("%p,%p\n", a[1],*(a+1));
}
*(a+i) 和 a[i] 是等价的
void main() {
int a[3][4] = {
{1,2,3,4},
{5,6,7,8},
{9,10,11,12}
};
printf("%d\n", *(*a+3));//4
printf("%d\n",*(*(a+1)));//5
printf("%d,%d\n", *a[2],*(*(a+2)));//9,9
}
用指向数组元素的指针变量输出二维数组各元素的值
void main() {
int a[3][4] = {
{1,2,3,4},
{5,6,7,8},
{9,10,11,12}
};
int* p;
for (p = a[0]; p < a[0]+12; p++)
{
if (p!=a[0] && (p - a[0]) % 4 == 0) {
printf("\n");
}
printf("%4d", *p);
}
}
通过用户输入确定元素的值
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
void main() {
int a[3][4] = {
{1,2,3,4},
{5,6,7,8},
{9,10,11,12}
};
int x, y;
scanf("%d,%d", &x, &y);
printf("(%d,%d)=%d\n",x,y,a[x][y]);
printf("(%d,%d)=%d\n",x,y,*(*(a+x)+y));
}
3个学生,各学4门课,计算总平均分数以及第n个学生成绩
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
void showscore();
void average();
void main() {
float score[3][4] = { {65,67,70,60}, {80,87,90,81},{90,99,100,98} };
average(*score, 12);
printf("\n");
showscore(*score, 1);
}
//计算平均数
void average(float* p, int n) {
float sum = 0, avg = 0;
float* p1;
for (p1 = p; p1 < p + n; p1++)
{
sum += *p1;
}
avg = sum / n;
printf("平均数:%f", avg);
}
void showscore(float* p, int n) {
float* p1 = p + n * 4;//确定第几个学员
for (int i = 0; i < 4; i++)
{
printf("%5.2f ", *(p1 + i));
}
}
遍历数组
形式参数是一个已定义大小的数组
void main() {
float score[3][4] = { {65,67,70,60}, {80,87,90,81},{90,99,100,98} };
//average(*score, 12);
//printf("\n");
//showscore(*score, 1);
sum1(score);
}
void sum1(float num[12]) {
double sum = 0;
for (size_t i = 0; i < 12; i++)
{
sum += num[i];
}
printf("%f", sum);
}
void main() {
float score[3][4] = { {65,67,70,60}, {80,87,90,81},{90,99,100,98} };
sum2(score);
}
void sum2(float num[3][4]) {
double sum = 0;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
sum += num[i][j];
}
}
printf("%f", sum);
}
嵌套for
void average1(float* p) {
float sum = 0, avg = 0;
float* p1 = p;
for (int i = 0; i < 3; i++)
{
p1 = p + (i) * 4;
for (int j = 0; j < 4; j++)
{
printf("%5.2f ", *(p1 + j));
}
printf("\n");
}
}
传入一维数组指针
void main() {
float score[3][4] = { {65,67,70,60}, {80,87,90,81},{90,99,100,98} };
sum3(score);
}
//二维数组的指针就是一个指向一维数组的指针
void sum3(float (*p)[4]) {
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
printf("%5.2f ", p[i][j]);
}
printf("\n");
}
}
几个例子
一维数组
void show(int a[10]) {
for (int i = 0; i < 5; i++)
{
printf("%d\n", a[i]);
}
}
void main() {
int num[5] = { 1,2,3,4,5 };
show(num);
system("pause");
}
二维数组
void show2(int score[2][3]) {
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
printf("%d\n", score[i][j]);
}
printf("\n");
}
}
void main() {
int score[2][3] = { {1,2,3},{3,4,5} };
show2(score);
system("pause");
}
一维数组名可以作为函数参数,多维数组名也可作函数参数。
用指针变量作形参,以接受实参数组名传递来的地址
数组作为函数参数,传递的是地址
void show(int *p) {
for (int i = 0; i < 5; i++)
{
//这里就是一位位移动
printf("%d\n", *(p + i));//printf("%d\n", p[i]);也是可以的
}
}
void main() {
int num[5] = { 1,2,3,4,5 };
show(num);
system("pause");
}
二维数组
void show(int(*p)[3]) {
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
printf("%5d", p[i][j]);
}
printf("\n");
}
}
void main() {
int score[2][3] = { {1,2,3},{3,4,5} };
show(score);
system("pause");
}
将数组num的数按反顺序输出
这里思路,就是数组折半,头尾互换
//数组没有副本,这里会直接修改原数据
void show(int a[],int n) {
for (int i = 0; i < n/2; i++)
{
int tmp = a[i];
a[i] = a[n - 1 - i];
a[n - 1 - i] = tmp;
}
}
void main() {
int num[5] = { 1,2,3,4,5 };
show(num, 5);
for (int i = 0; i < 5; i++)
{
printf("%d,", num[i]);
}
system("pause");
}
数组排序
void sort(int* p, int n) {
for (int i = 0; i < n-1; i++)
{
for (int j = 0; j < n-i-1; j++)
{
//主要在这里,判断前后两个数大小,交换
if (*(p + j) > *(p + j + 1)) {
int tmp = *(p + j);
*(p + j) = *(p + j + 1);
*(p + j + 1) = tmp;
}
}
}
}
void main() {
int num[6] = {21,22,3,84,15,60 };
sort(num, 6);
for (int i = 0; i < 6; i++)
{
printf("%d\n", num[i]);
}
system("pause");
}
函数指针
一个函数在编译时被分配一个入口地址,这个入口地址就称为函数的指针。
函数名代表函数的入口地址,这一点和数组一样。我们可以用一个指针变量来存放这个入口地址,然后通过该指针变量调用函数。
函数指针就是指向函数的指针变量。 因此“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向整型变量、字符型、数组一样,这里是指向函数。
void (*p)(int data);//函数指针
void show(int data) {
data = data + 100;
printf("%d", data);
}
void main()
{
p = show;//给函数指针赋值
(*p)(100);
getchar();
}
使用typedef
//typedef来定义一个指针函数
typedef int (*PAdd)(int x, int y);
int add(int x, int y) {
return x + y;
}
void main() {
PAdd p = add;
int sum=p(10, 20);
printf("%d", sum);
}
这里PAdd等于定义了一个新的类型
p = add可以理解为将函数指针 p 指向 add函数的地址,p(10,20);相当于执行add(10,20);
//typedef来定义一个指针函数
typedef int (*P)(int x, int y);
int add(int x, int y) {
return x + y;
}
int mul(int x, int y) {
return x * y;
}
void main() {
P p = add;
int sum=p(10, 20);
p = mul;
int rate = p(5, 20);
printf("%d,%d", sum,rate);
}
再来一个
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
void msg() {
MessageBoxA(0, "你过来呀!", "信息", 0);
}
void main() {
void (*p)() = msg;
p();
}
函数返回值
一个函数可以返回一个整型值、字符值、实型值等,也可以返回指针型的数据,即地址
int a = 10;
int b = 20;
//返回一个指针
int* cal() {
int c = a + b;
return &c;//这里是有风险的
}
void main() {
printf("%d", *(cal()));
getchar();
}
用指针作为函数返回值时需要注意的一点是,函数运行结束后会销毁在它内部定义的所有局部数据,包括局部变量、局部数组和形式参数,函数返回的指针请尽量不要指向这些数据
int a = 10;
int b = 20;
int c;
//返回一个指针
int* cal() {
c = a + b;
return &c;
}
void main() {
printf("%d", *(cal()));
getchar();
}
看一下这样会不会出问题
int a = 10;
int b = 20;
//返回一个指针
int* cal() {
int c = a + b;
return &c;//这里是有风险的
}
void main() {
int* p = cal();
printf("hi\n");
printf("%d", *p);//这里发现出问题了。
getchar();
}
在数组中找最大数
int* maxdata(int a[], int n) {
int* p = NULL;
int max = a[0];
p = &a[0];
for (int i = 0; i < n; i++)
{
if (max < a[i]) {
max = a[i];
p = &a[i];
}
}
return p;
}
void main() {
int a[8] = { 1,2,32,112,9,12,98,33 };
int* p = maxdata(a, 8);
printf("%d", *p);
}
字符串拷贝
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
void main() {
char s1[50];
strcpy(s1, "hello world");
printf("%s", s1);
}
手动一个方法
char* mcopy(char* source, char* dest) {
while (*source!='\0')
{
*dest++ = *source++;
}
}
void main() {
char s1[50] = "hello world";
char s2[50]="";
mcopy(s1, s2);
printf("%s\n", s1);
printf("%s", s2);
}
了解一个句柄
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
void main() {
HWND win;//就是指针
win = FindWindowA("Notepad", "Notepad");//找到一个窗口的句柄,也就是地址
if (win == NULL)
{
printf("没有找到Notepad");
}
else {
while (1)
{
ShowWindow(win, SW_HIDE);//控制隐藏与显示
Sleep(1000);
ShowWindow(win, SW_SHOW);
Sleep(1000);
}
}
}
Void与空指针
Void* 指针是一种特殊的指针,不指向任何类型的数据,如果需要用此地址指向某类型的数据,应先对地址进行类型转换。可以在程序中进行显式的类型转换,也可以由编译系统自动进行隐式转换。无论用哪种转换 大家必须了解要进行类型转换
指针变量可以有空值,即该指针变量不指向任何变量,可以这样表示:
p=NULL
用void一定要在取值时转换类型,其实就是确认长度
void main() {
int num = 10;
double db = 10.8;
int* p1 = #
void* p2 = p1;//可以接受任务类型地址
//printf("%d", *p2);//这里会出错,void没有类型
int* p3 = p2;
printf("%d\n", *p3);
printf("%d", *((int*)p2));//转换类型
}
void main() {
char ch = 'B';
int num = 99;
double db = 3.14;
//非常灵活,什么都可以指向
void* p;
p = &ch;
printf("%c\n", *((char *)p));
p = #
printf("%d\n", *((int*)p));
p = &db;
printf("%f\n", *((double*)p));
}
空指针
void main() {
int* p = NULL;
if (p == NULL) {
printf("指针为空!");
}
}
memset函数
void memset ( void *s , char ch, unsigned n )
函数功能:将s为首地址的一片连续的n个字节内存单元都赋值为ch
#include<stdio.h>
#include<stdlib.h>
void main() {
char s[50] = "hello world";
//从首地址开始,将前5个字符赋值成A
memset(s, 'A', 5);
printf("%s", s);
}
#include<stdio.h>
#include<stdlib.h>
void main() {
int a[10];
//这里为什么是40,因为a是int类型数组,
//每个元素是4个字节,所以int[10]实际是40个字节
//而memset接受的char只有1个字节
memset(a, 0, 40);
for (int i = 0; i < 10; i++)
{
printf("%d\t", a[i]);
}
}
这里有个坑,给0没问题,要是给1就出问题了,因为使用memset函数,对每个字节赋值为1。一个字节为8位,所以,数组变为
0000 0001 0000 0001 0000 0001 0000 0001