深入理解指针(4)
字符指针变量
#include<stdio.h>
int main()
{
char ch = 'h';
char* pch = &ch;
printf("%c\n",*pch);
*pch = 'g';
printf("%c\n",*pch);
return 0;
}
//结果为:
//h
//g
//也可以:
#include<stdio.h>
int main()
{
char* pch = 'h';
printf("%c\n",pch);
pch = 'g';
printf("%c\n",pch);
return 0;
}
//结果为:
//h
//g
数组指针变量
类比:
字符指针变量:char*:存放字符变量的地址—>指向字符变量的指针
整型指针变量:int*:存放整型变量的地址—>指向整型变量的指针
数组指针变量:存放数组的地址—>指向数组的指针
int arr[5] = {0};
int (*p)[5] = &arr;//数组的地址
//*说明p是指针变量,并非解引用
//p就是能够存放数组地址的一种指针变量--->数组指针变量
二维数组传参的本质
函数指针变量
函数指针是指向函数的,存放的是函数的地址
函数名是函数的地址,&函数名也是函数的地址,没有区别
int Add(int x,int y)
{
return x + y;
}
int main()
{
int a = 10;
int b = 20;
int (*pf)(int ,int) = &Add;
//pf就是函数指针变量
//一样;int (* pf)(int a,int b) = &Add;
//pf == Add,*说明pf是指针变量
return 0;
}
typedef关键字
unsigned int num;
typedef unsigned int uint;
int main()
{
unsigned int num;
uint num2;
return 0;
}
函数指针数组
转移表
简易计算器
#include<stdio.h>
void menu()
{
printf("------------------------\n");
printf("------1,Add 2,Sub------\n");
printf("------3,Mul 4,Div------\n");
printf("---------0,exit---------\n");
printf("------------------------\n");
}
int Add(int x, int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x - y;
}
int Mul(int x, int y)
{
return x * y;
}
int Div(int x, int y)
{
return x / y;
}
int main()
{
int input = 0;
do
{
menu();
printf("请选择:");
scanf("%d",&input);
int a = 0;
int b = 0;
int r = 0;
switch (input)
{
case 1:
printf("输入两个整数:");
scanf("%d %d",&a,&b);
r = Add(a, b);
printf("a+b=%d\n",r);
break;
case 2:
printf("输入两个整数:");
scanf("%d %d", &a, &b);
r = Sub(a, b);
printf("a-b=%d\n", r);
break;
case 3:
printf("输入两个整数:");
scanf("%d %d", &a, &b);
r = Mul(a, b);
printf("a*b=%d\n", r);
break;
case 4:
printf("输入两个整数:");
scanf("%d %d", &a, &b);
r = Div(a, b);
printf("a/b=%d\n", r);
break;
case 0:
printf("退出\n");
break;
default:
break;
}
} while (input);
return 0;
}
简易计算器的优化1
进行优化
仅需对主函数内部进行优化
int main()
{
int input = 0;
int (*pf_arr[])(int, int) = { 0,Add,Sub,Mul,Div };
do
{
menu();
printf("请选择:");
scanf("%d", &input);
int a = 0;
int b = 0;
int r = 0;
if (input == 0)
{
printf("退出\n");
}
else if (input >= 1 && input <= 4)
{
scanf("%d %d",&a,&b);
r = pf_arr[input](a,b);
printf("%d\n",r);
}
else
{
printf("输入不合法,重新输入\n");
}
} while (input);
return 0;
}
深入理解指针(5)
回调函数
回调函数就是一个通过函数指针调用的函数
简易计算器的优化2
void Calc(int (*pf)(int, int))
{
int a = 0;
int b = 0;
int r = 0;
printf("输入两个整数:");
scanf("%d %d", &a, &b);
r = pf(a, b);
printf("%d\n",r);
}
int main()
{
int input = 0;
do
{
menu();
printf("请选择:");
scanf("%d",&input);
switch (input)
{
case 1:
Calc(Add);
break;
case 2:
Calc(Sub);
break;
case 3:
Calc(Mul);
break;
case 4:
Calc(Div);
break;
case 0:
printf("退出\n");
break;
default:
break;
}
} while (input);
return 0;
}
qsort
使用示例
qsort
排序整型数据
#include<stdio.h>
#include<string.h>
int cmp_arr_by_int(const void* e1, const void* e2)
{
return (*(int*)e1 - *(int*)e2);
}
void Print_arr(int* arr,int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ",arr[i]);
}
printf("\n");
}
void test1()
{
int arr[10] = { 1,5,3,2,8,6,0,9,7,4 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_arr_by_int);
Print_arr(arr, sz);
}
int main()
{
test1();
return 0;
}
qsort
排序结构体数据
#include<stdio.h>
#include<stdlib.h>//使用struct结构体要包含的头文件
#include<string.h>//使用strcmp比较字符串要包含的头文件
struct Stu
{
char name[20];
int age;
};
int cmp_arr_by_name(const void* e1, const void* e2)
{
//比较两个字符串,前者大则返回>0的值,后者大则返回<0的值,相等返回0
//*(struct Stu*)e1).name,将e1强制类型转换为struct Stu*后解引用
return strcmp(((struct Stu*)e1)->name,((struct Stu*)e2)->name);
//也可以写成
//return strcmp((*(struct Stu*)e1).name,(*(struct Stu*)e2).name);
}
void Print_Stu(struct Stu* arr, size_t sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
//打印排序好的字符串
printf("%s " ,((arr[i]).name));
}
printf("\n");
}
void test()
{
struct Stu arr[3] = { {"zhangsan",18}, {"lisi",35},{"wangwu",12} };
int sz = sizeof(arr) / sizeof(arr[0]);
//使用qsort函数按照名字顺序排序
qsort(arr, sz, sizeof(arr[0]), cmp_arr_by_name);
Print_Stu(arr, sz);//打印排序好的字符串
}
int main()
{
test();
return 0;
}
qsort
函数的模拟实现
#include<stdio.h>
int cmp_int(const void* e1, const void* e2)
{
return (*(int*)e1 - *(int*)e2);
}
void Swap(void* e1,void* e2,int width)
{
int i = 0;
for (i = 0; i < width; i++)
{
char temp = *((char*) e1 + i);
*((char*) e1 + i) = *((char*) e2 + i);
*((char*) e2 + i) = temp;
}
}
int My_sort(void* base, size_t sz, size_t width,int(*cmp)(const void* e1, const void* e2))
{
int i = 0;
for (i = 0; i < sz - 1; i++)
{
int j = 0;
for (j = 0; j < sz - 1 - i; j++)
{
if (cmp((char*)base+j*width, (char*)base + (j+1) * width) > 0)
{
Swap((char*)base + j * width, (char*)base + (j + 1) * width,width);
}
}
}
}
void Print_arr(int* arr, int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
void test()
{
int arr[10] = { 1,5,3,2,8,6,0,9,7,4 };
int sz = sizeof(arr) / sizeof(arr[0]);
My_sort(arr,sz, sizeof(arr[0]),cmp_int);
Print_arr(arr,sz);
}
int main()
{
test();
return 0;
}
深入理解指针(6)
sizeof
和strlen
的对比
sizeof
是操作符,不关注内存中放的内容,只求所占内存空间的大小,单位是字节
strlen
是函数,求字符串长度,统计的是\0之前字符的个数,直到查找到\0,可能存在越界访问
一维数组
#include<stdio.h>
int main()
{
int a[] = { 1,2,3,4 };
printf("%zd\n", sizeof(a));//16字节
printf("%zd\n", sizeof(a + 0));//4/8
//a作为数组名,并未单独放在sizeof内部,a就是数组首元素的地址
//a+0还是数组首元素的地址,sizeof(a+0)计算的是一个地址的大小,那么就是4/8个字节
printf("%zd\n", sizeof(*a));//4
//a是数组首元素的地址,*a就是数组首元素,sizeof(*a)计算的是数组首元素大小,即4字节
printf("%zd\n", sizeof(a + 1));//4/8
//a就是数组首元素的地址,a+1就是第二个元素的地址,计算的是一个地址的大小,即4/8个字节
printf("%zd\n", sizeof(a[1]));//4
//sizeof(a[1])计算的是第二个元素的大小,即4字节
printf("%zd\n", sizeof(&a));//4/8
//&a取出的是整个数组的地址,是地址就是4/8字节
printf("%zd\n", sizeof(*&a));//16
//数组的地址解引用访问的是整个数组,大小是16字节
printf("%zd\n", sizeof(&a + 1));//4/8
//&a+1是数组的地址在跳过整个数组后的地址,是地址就是4/8字节
printf("%zd\n", sizeof(&a[0]));//4/8
//首元素地址,4/8字节
printf("%zd\n", sizeof(&a[0] + 1));//4/8
//第二个元素地址,4/8字节
return 0;
}
#include<stdio.h>
int main()
{
char arr[] = {'a','b','c,','d','e','f'};
printf("%zd\n",sizeof(arr));//6
//计算整个数组的大小
printf("%zd\n",sizeof(arr + 0));//4/8
//计算数组首元素地址
printf("%zd\n",sizeof(*arr));//1
//计算数组首元素大小
printf("%zd\n",sizeof(arr[1]));//1
//第二个元素大小
printf("%zd\n",sizeof(&arr));//4/8
//&arr是整个数组地址,是地址就是4/8字节
printf("%zd\n",sizeof(&arr + 1));//4/8
//跳过整个数组后的地址,4/8
printf("%zd\n",sizeof(&arr[0] + 1));//4/8
//第二个元素地址,4/8
return 0;
}
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = { 'a','b','c,','d','e','f' };
printf("%zd\n",strlen(arr));//没有\0随机值
printf("%zd\n",strlen(arr + 0));//没有\0随机值
//printf("%zd\n",strlen(*arr));//*arr是'a'ASSII值就是97,strlen会将97当做地址使用,这时就是非法访问
//printf("%zd\n",strlen(arr[1]));//同上,非法访问
printf("%zd\n",strlen(&arr));//没有\0随机值
printf("%zd\n",strlen(&arr + 1));//没有\0随机值
printf("%zd\n",strlen(&arr[0] + 1));//&arr[0] + 1得到第二个元素地址,没有\0,是随机值
return 0;
}
#include<stdio.h>
int main()
{
char arr[] = "abcdef";//字符串末尾隐藏着\0
printf("%zd\n",sizeof(arr));//7
printf("%zd\n",sizeof(arr + 0));//4/8
printf("%zd\n",sizeof(*arr));//1
printf("%zd\n",sizeof(arr[1]));//1
printf("%zd\n",sizeof(&arr));//4/8
printf("%zd\n",sizeof(&arr + 1));//4/8
printf("%zd\n",sizeof(&arr[0] + 1));//4/8
return 0;
}
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "abcdef";//字符串末尾隐藏着\0
printf("%zd\n", strlen(arr));//6
printf("%zd\n", strlen(arr + 0));//6
//printf("%zd\n", strlen(*arr));//得到'a'ASCII值是97.访问97这个地址,是非法访问
//printf("%zd\n", strlen(arr[1]));//得到'b'ASCII值是96.访问97这个地址,是非法访问
printf("%zd\n", strlen(&arr));//6
printf("%zd\n", strlen(&arr + 1));//跳过整个数组,\0位置不确定,随机值
printf("%zd\n", strlen(&arr[0] + 1));//5
return 0;
}
两种理解:
p[0]==*(p+0)
p[0],类似数组的下标访问==arr[0]
#include<stdio.h>
int main()
{
char* p = "abcdef";//字符串末尾隐藏着\0
printf("%zd\n",sizeof(p));//计算的是p这个指针变量的大小,4/8
printf("%zd\n",sizeof(p + 1));//p+1是第二个字符的地址,4/8
printf("%zd\n",sizeof(*p));//第一个字符a,是1
printf("%zd\n",sizeof(p[0]));//第一个字符a,是1
printf("%zd\n",sizeof(&p));//地址,4/8
printf("%zd\n",sizeof(&p + 1));//是b的地址,4/8
printf("%zd\n",sizeof(&p[0] + 1));//是b的地址,4/8
return 0;
}
#include<stdio.h>
#include<string.h>
int main()
{
char* p = "abcdef";//字符串末尾隐藏着\0
printf("%zd\n", strlen(p));//6
printf("%zd\n", strlen(p + 1));//5
//printf("%zd\n", strlen(*p));//*p,非法访问
//printf("%zd\n", strlen(p[0]));//p[0]->*(p+0)->*p,非法访问
printf("%zd\n", strlen(&p));//取得指针变量p的地址,是随机值
printf("%zd\n", strlen(&p + 1));//取得跳过这个字符串的地址,是随机值
printf("%zd\n", strlen(&p[0] + 1));//等同于p[1]指向的b的地址,5
return 0;
}
二维数组
#include<stdio.h>
int main()
{
int a[3][4] = { 0 };
printf("%zd\n",sizeof(a));//48,a是数组名,这里sizeof(a)中的a表示整个数组,计算的是整个数组大小
printf("%zd\n",sizeof(a[0][0]));//4,计算第一行第一列元素
printf("%zd\n",sizeof(a[0]));//16,a[0]作为第一行数组名,单独放在sizeof内部,就是计算第一行元素,第一行一共四列,即四个元素
printf("%zd\n",sizeof(a[0] + 1));//4/8,a[0]并未单独放在sizeof内部,表示首元素地址,即& a[0][0]加一后就是& a[0][1],是地址就是4/8字节
printf("%zd\n",sizeof(*a[0] + 1));//4,a[0] + 1是a[0][1]的地址,再解引用就是元素a[0][1]
printf("%zd\n",sizeof(a + 1));//4/8,a+1是第二行的地址,地址就是4/8字节
printf("%zd\n",sizeof(*(a + 1)));//16,计算的是第二行的元素
printf("%zd\n",sizeof(&a[0] + 1));//4/8,&a[0] + 1是第二行的地址,地址就是4/8字节
printf("%zd\n",sizeof(*(&a[0] + 1));//16,&a[0] + 1是第二行的地址,再解引用就是第二行
printf("%zd\n",sizeof(*a));//16,a是第一行的地址,*a就是计算第一行
printf("%zd\n",sizeof(a[3]));//16,类似于a[0],a[2]
//sizeof是根据类型来计算的长度的,即使只是一个表达式,编译器也会推算出最终的类型,来计算长度
return 0;
}
标签:arr,int,C语言,----,zd,地址,printf,sizeof,指针
From: https://blog.csdn.net/2401_88328558/article/details/144069696