StdC--11 指针基本知识(2)



Hightlight

1. Review & summary

2. 指针数组&数组指针(指向数组的指针)

3.数组和字符串

4. 函数指针(指向函数的指针)

5. 堆分配内存 malloc函数

6. 堆分配内存其他相关函数:
 6.1 calloc 函数
 6.2 realloc 函数

 



1. Review & summary
  1.1 指针作为形参  

    指针做为函数的形参 得到的是变量的地址 通过地址访问可以访问到原始变量 所以有机会修改到原始数据 (方法就是:对指针加*号 去操作数据)

  1.2 常量指针和指针常量  

    禁止通过指针修改一个变量的值 (*号左边) const T*p  

    希望指针本身是只读的: T* const P

  1.3 二级指针

    保存指针地址, 二级指针一般用于函数的形参

  1.4 void*

    可以是任意类型的地址, 取得变量之前必须做强制类型转换!

  1.5 指针数组: 保存一组指针

    e.g. 命令行参数  int main(int argc, char* argv[])

2. 指针数组&数组指针(指向数组的指针)

  2.1

    int * p[5];      //p是个数组,每个元素是int*

    int * p(double)  //p是一个函数 形参是double 返回类型是int*

    int(*P)[5];     //指向数组的指针,p是一个指针 指向5个元素的int数组 

    如何定义一个指向某种数组的指针:

      e.g. char a [20][10] ====> char(*p)[20][10]

  1 #include <stdio.h>
  2
  3 int main()
  4 {
  5     int *a[5];  //a是一个数组 5个元素 每个元素是int*
  6     int* f(double);
  7     int(*p)[5];  //p是一个指针 指向5个元素的int数组
  8
  9     int x[5]={11,22,33,44,55};
 10     int m;    //m是一个int 变量
 11     int* n;   //n是一个指针,指向int变量
 12     n=&m;    //?
 13
 14     int y[6]={12,23,34,45,56,67};
 15     int z[8][5];
 16
 17     p=&x;    //p是一个指针 指向5个元素的数组
                      //p=&x 表示第一个元素的地址
 18
 19     return 0;
 20     }    
  1 #include <stdio.h>
  2
  3 int main()
  4 {
  5     printf("abcxyz\n");
  6     printf("%p\n", "xyz");
  7
  8     *"abc"=‘x‘;    //字面值表示的字符串内容不可以修改, 导致core dump
  9     return 0;
 10 }

3.数组和字符串

 1 #include <stdio.h>
  2 int main()
  3 {
  4     char zi_fu_chuan[]="abc", xun_huan=0;
  5     printf("sizeof(zi_fu_chuan) is %d\n",sizeof(zi_fu_chuan));  //等价于:    char zi_fu_chuan[]={‘a‘,‘b‘,‘c‘,‘\0‘};   6     for(xun_huan=0;xun_huan<=3;xun_huan++)
7     {
  8         printf("%d ",zi_fu_chuan[xun_huan]);
  9         printf("%c /n",zi_fu_chuan[xun_huan]);
 10     }
 11     printf("\n");
 12     return 0;
 13 }
  1 #include <stdio.h>
  2
  3 int main()
  4 {
  5     char * p_zi_fu_chuan = "abc";
  6     char zi_fu_chuan[3]="abc";//没有\0的数组不能当字符串使用
  7     char zi_fu_chuan[]="abc";  
  9     printf("%s\n", p_zi_fu_chuan);
 10     printf("%s\n",zi_fu_chuan);
 11
 12     p_zi_fu_chuan=zi_fu_chuan;
 13     printf("%s\n",p_zi_fu_chuan);
 14     return 0;
 15
 16 }

安全读取字符串:

  1 #include <stdio.h>
  2
  3 int main()
  4 {
  5     char zi_fu_chuan[10];
  6     //scanf("%s",zi_fu_chuan);//不安全 容易造成溢出
  7     //gets(zi_fu_chuan);
  8     fgets(zi_fu_chuan, 10, stdin);  <-------------安全读取
  9     printf("%s\n",zi_fu_chuan);
 10     return 0;
 11 }

字符串函数练习

strlen()  strcat()  strncat()  strcpy()  strcmp()

  1 #include <stdio.h>
  2 #include <string.h>
  3
  4 int main()
  5 {
  6     char zi_fu_chuan[20]="abc";
  7     char zi_fu_chuan_1[]="xyz";
  8     printf("length(strlen): %d\n", strlen(zi_fu_chuan));
  9
//strcat可能溢出, 使用strncat()避免溢出
 10     printf("Merging(strcat): %s\n",strcat(zi_fu_chuan,zi_fu_chuan_1));
 11
 12     printf("Merging(strncat): %s\n", strncat(zi_fu_chuan,zi_fu_chuan_1    ,3));
 13
//strcpy 可能溢出, 使用strncpy()避免溢出
 14     printf("Coping(strcpy): %s\n",strcpy(zi_fu_chuan,zi_fu_chuan_1)); 

//比较两个字符串大小,前一个法则返回正,相等返回0,前一个小返回负数。可能溢出, 所以尽量使用strncmp来比较前几个字符
 16     printf("Comparing(strcmp): %d\n", strcmp(zi_fu_chuan,"xyz"));
 17     return  0;
 18 }

 Strcpy重写的练习

  1 #include <stdio.h>
  2
  3 char * str_cpy(char *p_zi_fu_chuan, char * p_zi_fu_chuan_1){
  4     if(!p_zi_fu_chuan||!p_zi_fu_chuan_1){    //避免空指针
  5         return p_zi_fu_chuan;
  67     char *p = p_zi_fu_chuan;
  8     while(*p_zi_fu_chuan_1!=0){
  9         *p_zi_fu_chuan = *p_zi_fu_chuan_1;
 10         p_zi_fu_chuan++;
 11         p_zi_fu_chuan_1++;
 12     }
 13     *p_zi_fu_chuan = ‘\0‘;
 14     return p;
 15 }
 16
 17 int main()
 18 {
 19     char zi_fu_chuan[10]="abc";
 20     printf("%s\n",str_cpy(zi_fu_chuan,"xy"));
 21     return 0;
 22 }

4. 函数指针(指向函数的指针)

  4.1 程序中定义一个函数,编译时编译系统为函数代码分配一段内存,此段内存的起始位置称为函数指针。

  4.2 定义

    int(*p)(int,int);  ==> p=max;

    p++, p--等没有任何意义

e.g. 函数指针的用途:

    用作比较的两个函数 仅仅只能通过修改代码的方式调用

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 void pai_xu(int shu_zi[],int size){
  4     if(1==bi_jiao(&shu_zi[0],&shu_zi[1]))
  5     {
  6         shu_zi[0]=shu_zi[0]^shu_zi[1];
  7         shu_zi[1]=shu_zi[0]^shu_zi[1];
  8         shu_zi[0]=shu_zi[0]^shu_zi[1];
  9     }
 10 }
 11
 12 int bi_jiao_1(const void * p_shu_zi_1, const void * p_shu_zi_2)
 13 {
 14     return (0 - bi_jiao(p_shu_zi_1,p_shu_zi_2));
 15 }
 16
 17 int bi_jiao(const void* p_shu_zi_1, const void* p_shu_zi_2){
 18     if(*(int*)p_shu_zi_1 > *(int*)p_shu_zi_2){
 19         return 1;
 20     }
 21     else if (*(int*)p_shu_zi_1 < *(int*)p_shu_zi_2){
 22         return -1;
 23     }
 24     else{
 25         return 0;
 26     }
 27 }
 28 int main()
 29 {
 30     int shu_zi[2]={7,2};
 31     int i=0;
 32     pai_xu(shu_zi,2);
 33     for(i=0;i<(sizeof(shu_zi)/sizeof(shu_zi[0]));i++){
 34         printf("%d is %d\n",i,shu_zi[i]);
 35     }
 36     return 0;
 37 }

如果想通过主函数调用来决定用哪一个函数那么就可以在排序函数里传递进一个比较函数的指针变量。

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 void pai_xu(int shu_zi[],int size,int (*p_func) (const void*, const void*)){                 //增加一个函数指针参数,调用函数时候传进哪个函数的指针就调用哪一个函数
  4     if(1==p_func(&shu_zi[0],&shu_zi[1]))  // 调用函数时候可以直接调用函数的指针
  5     {
  6         shu_zi[0]=shu_zi[0]^shu_zi[1];
  7         shu_zi[1]=shu_zi[0]^shu_zi[1];
  8         shu_zi[0]=shu_zi[0]^shu_zi[1];
  9     }
 10 }
 11
 12 int bi_jiao_1(const void * p_shu_zi_1, const void * p_shu_zi_2)
 13 {
 14     return (0 - bi_jiao(p_shu_zi_1,p_shu_zi_2));
 15 }
 16
 17 int bi_jiao(const void* p_shu_zi_1, const void* p_shu_zi_2){
 18     if(*(int*)p_shu_zi_1 > *(int*)p_shu_zi_2){
 19         return 1;
 20     }
 21     else if (*(int*)p_shu_zi_1 < *(int*)p_shu_zi_2){
 22         return -1;
 23     }
 24     else{
 25         return 0;
 26     }
 27 }
 28 int main()
 29 {
 30     int shu_zi[2]={7,2};
 31     int i=0;
 32     pai_xu(shu_zi,2,bi_jiao);
 33     for(i=0;i<(sizeof(shu_zi)/sizeof(shu_zi[0]));i++){
 34         printf("%d is %d\n",i,shu_zi[i]);
 35     }
 36
 37
 38     pai_xu(shu_zi,2,bi_jiao_1);  //主函数调用过程中可以仅需要传入指定参数
 39     for(i=0;i<(sizeof(shu_zi)/sizeof(shu_zi[0]));i++){
 40         printf("\n%d is %d\n",i,shu_zi[i]);
 41     }
 42
 43     return 0;
 44 }

  

  4.3 C语言的qsort函数 (对任何数量数组进行排序)

将上面例子替换成qsort函数

1 #include <stdio.h>
  2 #include <stdlib.h>
  3 void pai_xu(int shu_zi[],int size,int (*p_func) (const void*, const void*)){
  4     if(1==p_func(&shu_zi[0],&shu_zi[1]))
  5     {
  6         shu_zi[0]=shu_zi[0]^shu_zi[1];
  7         shu_zi[1]=shu_zi[0]^shu_zi[1];
  8         shu_zi[0]=shu_zi[0]^shu_zi[1];
  9     }
 10 }
 11
 12 int bi_jiao_1(const void * p_shu_zi_1, const void * p_shu_zi_2)
 13 {
 14     return (0 - bi_jiao(p_shu_zi_1,p_shu_zi_2));
 15 }
 16
 17 int bi_jiao(const void* p_shu_zi_1, const void* p_shu_zi_2){
 18     if(*(int*)p_shu_zi_1 > *(int*)p_shu_zi_2){
 19         return 1;
 20     }
 21     else if (*(int*)p_shu_zi_1 < *(int*)p_shu_zi_2){
 22         return -1;
 23     }
 24     else{
 25         return 0;
 26     }
 27 }
 28 int main()
 29 {
 30     int shu_zi[2]={7,2};
 31     int i=0;
 32     //pai_xu(shu_zi,2,bi_jiao);
 33     qsort(shu_zi,2,sizeof(int),bi_jiao);    //qsort只需要提供一个比较大小的函数即可
 34     for(i=0;i<(sizeof(shu_zi)/sizeof(shu_zi[0]));i++){
 35         printf("%d is %d\n",i,shu_zi[i]);
 36     }
 37
 38
 39     //pai_xu(shu_zi,2,bi_jiao_1);
 40     qsort(shu_zi,2,sizeof(int),bi_jiao_1);
 41     for(i=0;i<(sizeof(shu_zi)/sizeof(shu_zi[0]));i++){
 42         printf("%d is %d\n",i,shu_zi[i]);
 43     }
 44
 45     return 0;
 46 }

5. 堆分配内存 malloc函数

  --> 为了从对中分配变量使用函数malloc,需要一个参数指定序言分配的空间是多少个字节,它吧分配好的空间的首地址作为返回值。包含头文件 stdlib.h

  --> malloc() 有可能失败,如果失败返回NULL。

  --> 当使用完堆中的变量以后需要使用函数free, 把占用空间释放掉

  --> free函数不会把原来指针中的地址设置为NULL,仅仅把空间释放掉。 释放掉后吧指针设置成空

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3
  4 int main()
  5 {
  6     //int shu_zi[3]={0},xun_huan=0; //分配在栈上
  7     int * shu_zi=NULL, xun_huan=0;
  8     (int*) malloc(3*sizeof(int));  //分配内存在堆上,从堆中分配3个整数变量
  9
 10     if(!shu_zi){ //如果返回空指针 说明malloc失败 所以每次malloc时候要做判断
 11         printf("malloc failed \n");
 12         return 0;
 13     }
 14
 15     for(xun_huan=0;xun_huan<3;xun_huan++){
 16         printf("please enter one number: \n");
 17         scanf("%d",shu_zi+xun_huan);
 18     }
 19
 20     for(xun_huan=2;xun_huan>=0;xun_huan--){
 21         printf("%d",shu_zi[xun_huan]);
 22     }
 23     free(shu_zi);  //释放
        shu_zi =null;   //释放之后要把指针变量设置成NULL
 24     return 0;
 25 }

6. 堆分配内存其他相关函数:

  6.1 calloc 函数

    calloc函数可以用于从堆中分配变量而且分配的变量都一定是被清0的

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3
  4 int main()
  5 {
  6     int * p_shu_zi = NULL, ge_shu=0,xun_huan;
  7     p_shu_zi=(int*)malloc(3*sizeof(int));    //不保证变量都被清0
  8     p_shu_zi= (int*)calloc(3,sizeof(int));    //保证所有变量都被清0
  9
 10     if(p_shu_zi){
 11         for(xun_huan=0;xun_huan<=2;xun_huan++){
 12             printf("%d\n", *(p_shu_zi+xun_huan));
 13         }
 14         free(p_shu_zi);
 15         p_shu_zi=NULL;
 16     }
 17
 18     return 0;
 19 }
~              

 6.2 realloc 函数

  realloc(p_shu_zi,6*sizeof(int));

  --> 第一个参数为原变量首地址, 第二个参数为要调整成多大

  --> 如果原来的地址后面正好有空位 那么就会把后面内存加上

    如果原来的地址后面没有空位那么久从新找6个int位 并且把原来的地址释放掉。

  --> realloc 如果失败之后会返回NULL, 那么是否可以把原来指针直接付给realloc的返回值?

    p_shu_zi= realloc(p_shu_zi,6*sizeof(int));

    不可以这样, 如果调用失败的话那么p_shu_zi就为空,原来地址就泄露

  --> 如果realloc的第二个参数为0, 效果类似free

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3
  4 int main()
  5 {
  6     int * p_shu_zi = NULL, ge_shu=0,xun_huan;
  7     //p_shu_zi=(int*)malloc(3*sizeof(int));
  8     p_shu_zi= (int*)calloc(3,sizeof(int));
  9
 10     if(p_shu_zi){
 11         for(xun_huan=0;xun_huan<=2;xun_huan++){
 12             printf("%d\n", *(p_shu_zi+xun_huan));
 13             *(p_shu_zi+xun_huan)=xun_huan+1;
 14         }
 15         printf("\n\n");
 16         int *p_shu_zi_1=realloc(p_shu_zi,6*sizeof(int) );//把3个整数的空间调整为6个
 17         if(p_shu_zi_1)//如果realloc成功
 18         {
 19             printf("%p %p \n", p_shu_zi, p_shu_zi_1);
 20             p_shu_zi=p_shu_zi_1;//用新地址覆盖掉旧地址
 21
 22             for(xun_huan=0;xun_huan<=5;xun_huan++){
 23                 printf(" %d \n", *(p_shu_zi+xun_huan));
 24             }
 25         }
 26
 27         free(p_shu_zi);
 28         p_shu_zi=NULL;
 29     }
 30
 31     return 0;
 32 }

6. 二维指针-续

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3
  4 void chai_fen(char* zi_fu_chuan, char **pp_zi_fu)
  5 {
  6     int i=0;
  7     while(*(zi_fu_chuan+i)!=‘:‘){
  8         i++;
  9     }
 10
 11     char *p_zi_fu=NULL;
 12     p_zi_fu=(char*)malloc(i+1);
 13     i=0;
 14     while(*(zi_fu_chuan+i)!=‘:‘){
 15         *(p_zi_fu+i)=*(zi_fu_chuan+i);
 16         i++;
 17     }
 18     *(p_zi_fu+i)=0;
 19     *pp_zi_fu=p_zi_fu;
 20 }
 21
 22 int main()
 23 {
 24     char zi_fu_chuan[]="1234:5678:9012";
 25     char *p_zi_fu=NULL;
 26
 27     chai_fen(zi_fu_chuan, &p_zi_fu);
 28     printf("the result is : %s\n", p_zi_fu);
 29     free(p_zi_fu);
 30     p_zi_fu=NULL;
 31     return 0;
 32 }
时间: 2024-10-11 02:50:25

StdC--11 指针基本知识(2)的相关文章

C-09 指针基本知识(1)

Hightlight 1.1 自我理解的指针概念 1.2 如果用不同类型的数据来赋值指针 1.3 野指针 1.4 悬空指针 1.5 地址(指针)作为参数 1.6 数组作为形参 1.7 常量指针和指针常量 1.8 举例: 排序一组数据 数据都是const类型 不能改变数据的情况下排序 1.9 主方法参数 1.10 strcmp()函数 1.11 二级指针 1.12 Void* 类型 1.13 Assignment 1. 指针基本知识 1.1 自我理解的指针概念 保存地址的变量叫指针 指针作为数据用

二级指针基础知识

/* ============================================================================ Name : TestDoublePointer.c Author : lf Version : Copyright : Your copyright notice Description : 二级指针基础知识 ================================================================

指针基础知识

1 #include <iostream> 2 using namespace std; 3 4 int main() 5 { 6 int num = 20; 7 int *p = &num; //存储num的地址 8 cout<< num <<endl; 9 cout<< p <<endl; //输出指针存储的地址 10 cout<< *p <<endl; //输出指针地址的值 11 return 0; 12 }

11个小知识帮助你Python快熟入门

随着移动互联网的普及,服务器运维所面临的挑战也随之越来越大.当规模增长到一定程度,手动管理方式已经无法应对,自动化运维成为解决问题的银弹.Python凭借其灵活性,在自动化运维方面已经被广泛使用,能够大大提高运维效率,服务器集群的规模越大,优势越明显.下面一些知识有助于你开始进入Python的世界. 1 Python适用于哪些应用场景? 这个没有固定答案,很多人都说Python不适合开发GUI的程序,但Python自己的IDE--IDEL和第三方的IDE--Eric就是Python写的. 目前看

C++11 指针成员与拷贝构造(浅拷贝与深拷贝)

[1]浅拷贝 一直以来,设计一个类,个人认为,最能体现水平的地方在于:类中含有指针成员变量. 如下一个典型的浅拷贝示例: 1 #include <iostream> 2 using namespace std; 3 4 class HasPtrMem 5 { 6 public: 7 HasPtrMem() : d(new int(0)) 8 {} 9 ~HasPtrMem() 10 { 11 delete d; 12 d = nullptr; 13 } 14 15 int* d; 16 };

实验11——指针的基础应用

1.本次课学到的知识点: (1)指针是c语言中非常重要的概念,使用指针可以对复杂数据进行处理,能对计算机的内存分配进行控制,在函数调用中使用指针还可以返回多个值. (2)指针访问内存和操纵地址,是通过变量的地址进行操控. (3)指针变量:变量p是用来存放地址的变量,实现对变量的间接操作. (4)指针变量定义: 类型名  *指针变量名: 类型名指定指针变量所指向的变量的类型,必须是有效数据类型:int,float,char等. 2. 实验过程中遇到的问题及解决方法:对指针还不是很熟悉,可以理解定义

指针相关知识

1.指针:内存地址 指针变量:专门用一个变量来存放指针,这种变量成为指针变量.因此,一个指针变量的值就是某个内存单元的地址(或指针) “指针”是指地址,是常量,“指针变量”是指取值为地址的变量 2.二级指针 指针变量中主要存放目标变量的地址,这种指针称为一级指针.如果指针变量中存放的不是变量的地址,而是存放一级指针变量的地址,则这种指针称为二级指针. 格式: [存储类型]  数据类型符    **变量名: 例如: int a=5; int *p1; int **p2; p1=&a; p2=&

【C语言】【指针相关知识小结】

1.int *p = NULL 和 *p = NULL的区别 int *p = NULL指的是将一个指针初始化为NULL,具体过程为 int *p; p = NULL. 2.&a与a的区别 int a[5]; int *p = &a;//?? int *q = a;//?? 这样的代码对吗? 解释: &a得到数组的地址. a表示数组首元素的首地址. &a的a的值一样,两个指向的位置是相同的,但是意义不同. 3.指针和数组的定义与声明 什么是声明和定义: C语言中的对象必须只

Boost智能指针-基础知识

简单介绍 内存管理一直是 C++ 一个比較繁琐的问题,而智能指针却能够非常好的解决问题,在初始化时就已经预定了删除.排解了后顾之忧.1998年修订的第一版C++标准仅仅提供了一种智能指针:std::auto_ptr(现以废弃),它基本上就像是个普通的指针:通过地址来訪问一个动态分配的对象. std::auto_ptr之所以被看作是智能指针.是由于它会在析构的时候调用delete操作符来自己主动释放所包括的对象. 当然这要求在初始化的时候,传给它一个由new操作符返回的对象的地址.既然std::a