评论

收藏

[C++] C语言指针进阶2

编程语言 编程语言 发布于:2021-12-17 10:10 | 阅读数:534 | 评论:0

qsort函数的使用
使用qsort函数
int cmp(const char* e1, const char* e2)
{
  return *((int*)e2) - (*(int*)e1);
}
void print(int* arr,int sz)
{
  int i = 0;
  for (i = 0;i < sz; i++)
  {
  printf("%d ", arr[i]);
  }
}
int main()
{
  int arr[] = { 1,2,3,4,5,6,7,8,9 };
  int sz = sizeof(arr)/sizeof(arr[0]);
  qsort(arr,  sz,    sizeof(arr[0]),   cmp);//cmp表示另外一个函数
    数组  元素个数  单个元素的大小   比较数组中相邻连个元素的大小
  print(arr,sz);
  return 0;
}
qsort函数的制造
struct stu
{
  char name[20];
  int number;
};
//比较int类型
int arrint_cmp(const void* e1, const void* e2)
{
  return *(int*)e2 - *(int*)e1;
}
//比较结构体类型中的字符串
int struct_strcmp(const void* e1, const void* e2)
{
  return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);
  //这里形参时整个分支,但是在比较的时候,只用其中一个分支的某一个变量
  //这利用的就是name,以为是一个字符串,所以只比较首个字符的大小
}
//比较结构体中的数字
int struct_intcmp(const void* e1, const void* e2)
{
  return ((struct stu*)e1)->number - ((struct stu*)e2)->number;
}
//交换函数
void swap(char* a,char*b, int width)
{
  int i = 0;
  for (i = 0;i < width;i++)
  {
  char tmp = *a;
  *a = *b;
  *b = tmp;
  a++;
  b++;
  }
}
//写的qsort
void my_qsort(void* arr,int sz,int width,int(*p)(void*,void*))
{
  int i = 0, j = 0;
  for (i = 0;i < sz - 1;i++)//循环次数
  {
  for (j = 0;j < sz - 1 - i;j++)//进行的各个交换
  {
    if ((*p)(((char*)arr+j*width),((char*)arr + (j+1) * width)) > 0)
    //在这里只是判断这个返回值的大小,里面的函数传结构体的时候,将结构体中的一整个分支都传过去
    {
    //在比较收个字符大小之后,再将两个分支传递给交换函数,将整个分支进行交换
    swap(((char*)arr + j * width), ((char*)arr + (j+1) * width),width);
    }
  }
  }
}
//打印函数
void print(int* arr, int sz)
{
  int i = 0;
  for (i = 0;i < sz; i++)
  {
  printf("%d ", arr[i]);
  }
}
//按结构体中的两种不同类别经i性能排序
void struct_str_text()
{
  struct stu s[3] = { {"zhangsan",20},
      {"lisi",19},
      {"wangwu",18} };
  int sz1 = sizeof(s) / sizeof(s[0]);
  //按字符串排序
  //my_qsort(s, sz1, sizeof(s[0]), struct_strcmp);
  //按数字排序
  my_qsort(s, sz1, sizeof(s[0]), struct_intcmp);
  //printf("%s ", s.number);
  
}
//按数组进行排序
void arr_int_text()
{
  int arr[] = { 1,2,3,4,5,6,7,8,9 };
  
  int sz = sizeof(arr) / sizeof(arr[0]);
  my_qsort(arr, sz, sizeof(arr[0]), arrint_cmp);//cmp表示另外一个函数
  //   数组  元素个数  单个元素的大小   比较数组中相邻连个元素的大小
  print(arr, sz);
  
}
//主函数调用
int main()
{
  //arr_int_text();
  struct_str_text();
  return 0;
}
指针深度理解
int main()
{
  /*int arr[] = { 1,2,3,4,5,6,7 };*/
  printf("%d\n", sizeof(arr));// 28 这里的arr是整个数组的地址,计算的也是整个数组中所有元素的地址字节总和,int类型4*个数7==28
  printf("%d\n", sizeof(arr+0));//4 这里代表的是首元素的地址+0还是首元素的地址,地址是4字节
  printf("%d\n", sizeof(*arr));// 4 这里还是首元素的地址,取内容得到1由于是int类型得到4
  printf("%d\n", sizeof(arr[1]));//4 同上,但是得到的是第二个元素的值
  printf("%d\n", sizeof(arr+1));//4 
  printf("%d\n", sizeof(&arr));//4 这里是整个元素的地址,无论是谁都是4/8
  printf("%d\n", sizeof(&arr+1));//4 同上,但是跳过了整个数组
  printf("%d\n", sizeof(*&arr));//28,可以想象成两个符号相抵消,int类型4*个数7==28
  printf("%d\n", sizeof(&arr[0]));//4 
  printf("%d\n", sizeof(&arr[0]+1));//第一个元素的地址,跳过类一个数组
  char arr1[] = { 'a','b','c','d' };
  printf("%d ", sizeof(arr1));//4 这里是
  上下两种意思不同,上面的是个数乘以类型字节
  下面的意思是地址
  printf("%d ", sizeof(arr1+1));//3////这的意思是首元素地址,+1跳还是地址
  printf("%d ", sizeof(*arr1));//1
  printf("%d ", sizeof(arr1[1]));//1
  printf("%d ", sizeof(&arr1));//4
  printf("%d ", sizeof(&arr1 + 1));//4
  printf("%d ", sizeof(&arr1[0] + 1));//4
  char arr1[] = { 'a','b','c','d' };
  //strlen函数是接受的一个地址
  printf("%d ", strlen(arr1));//sui
  printf("%d ", strlen(arr1 + 1));// sui
  printf("%d ", strlen(*arr1));//err
  printf("%d ", strlen(arr1[1]));//err
  printf("%d ", strlen(&arr1));//sui
  printf("%d ", strlen(&arr1 + 1));//sui
  printf("%d ", strlen(&arr1[0] + 1));//sui
  char arr1[] = "abcd";
  //&arr1就是整个地址,跳的话也是整个地址
  //strlen函数是接受的一个地址
  printf("%d ", strlen(arr1));//4
  printf("%d ", strlen(arr1 + 1));//3
  //printf("%d ", strlen(*arr1));//err
  //printf("%d ", strlen(arr1[1]));//err
  printf("%d ", strlen(&arr1));//4
  printf("%d ", strlen(&arr1 + 1));//sui
  printf("%d ", strlen(&arr1[0] + 1));//3
  /*char* p="abcd";char* p="abcd";*/
  printf("%d ", sizeof(p));//4 这里是地址
  printf("%d ", sizeof(p + 1));//4
  printf("%d ", sizeof(*p));//1//这里是首元素的地址,取内容是a,类型是char
  printf("%d ", sizeof(p[1]));//1
  printf("%d ", sizeof(&p));//4
  printf("%d ", sizeof(&p + 1));//4
  printf("%d ", sizeof(&p[0] + 1));//4
  char* p = "abcd";
  printf("%d\n", strlen(p));//4
  printf("%d\n", strlen(p+1));//3
  //printf("%d\n", strlen(*p));//err
  //printf("%d\n", strlen(p[1]));//err
  printf("%d\n", strlen(&p));//sui
  printf("%d\n", strlen(&p+1));//sui
  printf("%d\n", strlen(&p[0]+1));//3
  int a[3][4] = { 0 };
  printf("%d\n", sizeof(a));//3*4*4
  printf("%d\n", sizeof(a[0][0]));//4
  printf("%d\n", sizeof(a[0]));//16//二维数组第一个元素,是整个第一个二级数组,sizeof(int)*列
  printf("%d\n", sizeof(a[0]+1));//4,地址
  printf("%d\n", sizeof(*(a[0] + 1)));//4,类型大小
  printf("%d\n", sizeof(a + 1));//4,地址
  printf("%d\n", sizeof(*(a + 1)));//16//这里的a是二维数组首元素地址即整个二级数组的地址在取内容
  printf("%d\n", sizeof(&a[0]+1));//4
  printf("%d\n", sizeof(*(&a[0] + 1)));//16
  printf("%d\n", sizeof(*a));//16
  printf("%d\n", sizeof(a[3]));//16
  //任何一个表达式都有两个表达式1、值属性2、类型属性
  // sizeof(a[3])这里是用类型属性计算出来的
  //sizeof()括号里面的是不会真正去计算的
  return 0;
}
总结
:再求这种题的时候只有两种特殊情况
1、sizeof(arr)这里求的是整个元素占多少字节
2、&arr这里求的是整个数组的地址+1跳的也是真个数组

强制类型转换时的指针
struct text
{
  char name[10];
}*p;
int main()
{
  printf("%d\n", p);//
  printf("%d\n", p + 0x1);//p的类型是指针+1跳过了一整个数组
  printf("%d\n", (unsigned int)p + 0x1);//转换成了unsigned int 加1就是+1
  printf("%d\n", (unsigned int*)p + 0x1);
  //这里转换成了unsigned int*+1就是跳过了unsigned int*的步长
  return 0;
}
int main()
{
  //这里是小端存储(小端的一边数字权重比较小)
  //所以我们按左端是小端而右边是大端
  
  int arr[] = { 1,2,3,4 };//00 00 00 00 
  int* prt = (int*)(&arr + 1);
  int* prt1 = (int*)((int)arr + 1);
  printf("%x\n",prt[-1]);//4   //指针先以整个数组的大小进行跳跃,跳到最后,再转换成int*类型-1向后跳跃4个字节,在以16进制进行读取
  //00 00 00 01|00 00 00 02|00 00 00 03|00 00 00 04|先跳到最后面在转换成int*-1向后移动1个int*的步数,在往后面读取
  
  //地址里本来就是16进制进行储存的,打印的话格式按照16进制才能打印出来
  printf("%x\n",prt1[0]);
  //2 00 0000 这里先把数组首元素地址转换成int类型在+1就是一个字节,再转换成int*类型向后读取4个字节里面的内容,那个2就在读取的最后一个字节里面
  //01 00 00 00|02 00 00 00|03 00 00 00|04 00 00 00|
  //  |00 00 00 02|加一就像后面移动了1位读取后的结果,
  //在字节内中读取的时候是从左向右即从地址小的地方开始读取 
  //在地址里面,每一次以int类型+1,就相当于跳跃一个char*类型
  //因为每一个地址对应一个字节
  //1个字节8位,每四位也就是总共15是一个字节 00 ,两位中的其中一位
  return 0;
}
int main()
{
  int a[5][5];
  int(*p)[4];
  p = a;
  printf("%p\n%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
  //这里的的负数存在内存中的时候,是存的-4,读取的时候是-4但是在以16进制打印的是偶
  printf("%d\n", sizeof(&p[4][2] - &a[4][2]));
  return 0;
}
DSC0000.png
int main()
{
  int arr[2][5] = { 1,2,3,4,5,6,7,8,9,10 };
  int* ptr1 = (int*)(&arr + 1);
 //整个数组的地址+1跳过整个数组,再转换成int*,-1后退一个int类型即4个字节就是10
  int* ptr2 = (int*)(*(arr + 1));
 //首元素的地址+1跳过一个二级数组,换成int*-1,后退一个int类型即4个字节就是5
  printf("%d %d", *(ptr1 - 1), *(ptr2 - 1));
  return 0;
}
数据结构的知识补充
int main()
{
  char a = 128;
  printf("%u", a);
  printf("%d", a);
  printf("%p", a);
  //1、内存里面存的是什么
  //2、打印的时候按什么格式打印的
  
  //村进入内存的时候是10000000
  //以16进制打印
  //在以16进制打印的时候不会再转换成原码,而是直接以补码形式打印
  
  //有符号形式打印
  //11111111 11111111 11111111 10000000
  //10000000 00000000 00000000 01111111
  //10000000 00000000 00000000 10000000
  //无符号形式打印
  //00000000 00000000 00000000 10000000
  //11111111 11111111 11111111 01111111
  //11111111 11111111 11111111 10000000
  return 0;
}
int main()
{
  int a = -128;
  printf("%u\n", a);
  //10000000 00000000 00000000 10000000
  //11111111 11111111 11111111 01111111
  //11111111 11111111 11111111 10000000(存进去)(补码)
  //以无符号形式打印,会直接打印补码(对于无符号整形就是正数),不会再转化成原码就是补码
  printf("%d\n", a);
  //10000000 00000000 00000000 10000000
  //11111111 11111111 11111111 01111111
  //11111111 11111111 11111111 10000000(存进去)(补码)
  //10000000 00000000 00000000 01111111
  //10000000 00000000 00000000 10000000(原码打印)-128
  printf("%p\n", a);
  //00000000 00000000 00000000 10000000
  //11111111 11111111 11111111 01111111
  //11111111 11111111 11111111 10000000(存进去)(补码)
  //直接补码打印
  return 0;
}
指针指向多个字符串的数组
int main()
{
  char* arr[] = { "abc","at","bgv" };//本句的意思是arr是一个数组,里面存放的是char*类型的元素
  //所以数组里面存放的都是三个元素的首地址,arr可以看作成二级数组
  
  char** p = arr;
  //arr是数组首元素的地址,将数组首元素的地址(首元素存放的还是一个地址,关于字符串的),存放到p里面,所以p就是char**
  //由此可以看出,可以根据指针的类型判断出所指向的元素的类型
  p++;//p是首元素的地址,p++,就是首元素地址+1
  printf("%s", *p);//p取内容,第二个元素的地址取内容,就是第二个字符串
  return 0;
}
1、指针在定义的时候,一共有几颗星,解引用(几-1)次,就可以得到内容
2、在指针定义的过程中,完全可以在脑海中补引入第三个盒子,相当于,把所要只想的东西提出来(掰开一般出来),一半就是另一半

数组指针和指针
int main()
{
  int* p = NULL;
  int arr[10] = { 0 };
  return 0;
}
A.p=arr
这里的arr是一个数组首元素的地址,类型是int*所以p可以指向
B.int(*ptr)[10]=&arr
&arr是整个数组的地址,指向整个数组的地址的指针是必须是一个数组指针,所以符合
C.p=&arr[0]
同A
D.p=&arr
这里的p只是一个int*类型的指针,不是数组指针所以错误


关注下面的标签,发现更多相似文章