在这篇博客里面,我主要讲一下值传递,参数传递
一步一步深入剖析,全部由代码来说话
#include <stdio.h>
#include <stdlib.h>

//这里为形参重新分配一个存储单元
//所以形参的改变不影响实参
//所以得到的打印值是a1=0,a2=0
void swap1(int x,int y)
{
            x=1;
            y=1;
}

//一级指针x指向的是a的地址
//*x就是a的地址中存的值,也就是a的值,
//所以改变*x就是改变a的值
void swap2(int *x,int *y)
{
            *x=2;
            *y=2;
}

//这里直接就是x和a指向同一片内存区,
//x只不过是a的别名,所以改x就是改a
//但是这个在c里面是编译通不过的,因为c里面还没有引用
//可惜,我觉得引用真是个好东西
void swap3(int &x,int &y)
{
             x=3;
             y=3;
}

int main()
{
         int a=0,b=0;
    
         swap1(a,b);
         printf("a1=%d,b1=%d\n",a,b);
//这里一定要注意,如果传的参数是a,b,编译也不会出错,因为a,b和地址一样,都是int类型
//只是把a,b的值当地址传,传的地址是不对的,会出现segmentation fault
         swap2(&a,&b);
         printf("a2=%d,b2=%d\n",a,b);
    
         swap3(a,b);
         printf("a2=%d,b2=%d\n",a,b);
}

在进一步,传指针的时候怎么办?
#include <stdio.h>
#include <stdlib.h>

//这里新建一个指针,因为函数调用的原因,初始化指向NULL
//但是在函数里面,指针指向了新的地址&temp
//但是,和实参a没有什么关系
//所以a的地址依旧为NULL(0),
//问这个地址中的值,当然会出现segmentation fault
void func1(int *x)
{
            int temp=11;
            printf("&temp=0x%x\n",&temp);
            x=&temp;
}

//执行函数调用为int **x=&a
//x为二级指针,所指向的地址为&a,也就是存一级指针的那个地址
//*x为一级指针,为*(&a)=a;所指向的地址为存int类型值的那个地址
//a原本是指向NULL的,但是这里*x=a把它强制指向了另外一个地址&temp
//这样实参a的地址的得到了改变,可是值不是22
//因为temp这里是栈,函数过了,站也就销毁了,所以值就靠不住了
//怎么办?
//temp移到全局区域去,这样就是堆了,要不malloc,也是堆
void func2(int **x)
{
            int temp=22;
            printf("&temp=0x%x\n",&temp);
            (*x)=&temp;
    
}

//这个函数就是用malloc来实现堆的
//给*x=a重新malloc一片存储区,然后指定这个地址上存33这个数
void func3(int **x)
{
            *x=(int *)malloc(4);
            **x=33;
}
int main()
{
         int *a;
         a=NULL;
/*    
         func1(a);
         printf("0x%x\n",a);
         printf("%d\n",*a);
*/
/*
         func2(&a);
         printf("0x%x\n",a);
         printf("%d\n",*a);
*/
///*
         func3(&a);
         printf("0x%x\n",a);
         printf("%d\n",*a);
//*/
}
最后,我举一个单链表的操作的实例,以为我觉得它也是涉及二级指针中一个蛮不错的例子,而且我在网上都没有找到在我的电脑上立马编译通过,可以执行年该的单链表的例子,就从网上下了一个,然后改了下
#include<stdio.h>
#include<stdlib.h>

#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define LIST_INIT_SIZE 100 //线性表存储空间初始分配量
#define LISTINCREMENT 10     //线性表存储空间的分配增量

typedef int Status;
typedef int ElemType;
typedef struct LNode
{
      ElemType    data;
      struct LNode    *next;
}LNode,*LinkList;

Status printf_L(LinkList L)
{
       //输出单链表L中的元素
       LinkList p=L;
       while(p->next)
       {
            p=p->next;
            printf("%d,",p->data);
       }
       printf("\n");
       return OK;
}//printf_L
void CreateList_L(LinkList *L)
{
        //单链表初始化
        //逆位序输入n个元素的值,建立带表头结点的单链线性表L
        int i,n;
        (*L)=(LinkList)malloc(sizeof (LNode));
        (*L)->next=NULL;                    //建立一个带头结点的单链表
        printf("n=");
        scanf("%d",&n);
        printf("\ndata=");
        for(i=n;i>0;--i)
        {
              LinkList p=(LinkList)malloc(sizeof(LNode));    //生成新结点                                                        
              scanf("%d",&(p->data));                       //输入元素值
              p->next=(*L)->next;                            //插入到表头
              (*L)->next=p;
         }
}//CreateList_L

Status ListInsert_L(LinkList *L,int i,ElemType e)
{
          //在带头结点的单链线性表L中第i个位置之前插入元素e
          LinkList p=(*L);
          int j=0;
          while(p&&j<i-1)
          {
               //寻找第i-1个结点
               p=p->next;
               ++j;
           }
           if(!p||j>i-1)
                 return ERROR;                   //i小于1或者大于表长+1
           LinkList s;
           s = (LinkList)malloc( sizeof (LNode)); //生成新结点
           s->data=e;
           s->next=p->next;
           p->next=s;
           return OK;
}//ListInsert_L

Status ListDelete_L(LinkList *L,int i,ElemType *e)
{
          //在带头结点的单链线性表L中,删除第i个元素,并由e返回其值
          LinkList p=(*L);
          int j=0;
          while (p->next&&j<i-1)
          {
               //寻找第i-1个结点,并令p指向其前驱
               p=p->next;
               ++j;
          }
          if(!(p->next)||j>i-1) return ERROR; //删除位置不合理
          LinkList q=p->next;                      //删除并释放结点
          p->next=q->next;
          (*e)=q->data;
          free(q);
          return OK;
}//ListDelete_L

int main()
{
         LinkList La,Lb;
         int e;
         //创建一个链表,并且插入
         CreateList_L(&La);
         printf("\nLa=");
         printf_L(La);

         ListInsert_L(&La,3,7);//往第三个结点处插入7
         printf("\nInsetLa=");
         printf_L(La);
         printf("\n");

         //创建一个链表,并且删除  
         CreateList_L(&Lb);
         printf("\nLb=");
         printf_L(Lb);
         ListDelete_L(&Lb,4,&e);//删除第四个结点,并得到第四个结点的值
         printf("\nDeleteLb=");
         printf_L(Lb);

         return 0;
}