C语言基础(六)

//
//  main.c
//  C_05_02
//
//  Created by 8011 on 15/12/2.
//  Copyright © 2015年 yong. All rights reserved.
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    
    int num;
    char *name;
    char sex;
    float score;
}Student;


int *getArray();
void printBookName(char *name[],int count);
void sortBookName(char *name[],int count);
void print(Student *stu);


int main(int argc, const char * argv[]) {
    
    /*
     1.动态内存
     2.字符串与指针
     3.指针作为函数返回值
     4.指针数组
     5.数组指针
     6.指针的指针
     7.结构体指针
    */
    int i = 10;
    int *p = &i;
    
    /*
     动态分配内存
        它就是跟系统申请一块内存,然后将该块内存的起始地址给了p.而这个地址不是固定的,所以称为动态分配内存.
     动态分配内存涉及到几个常用函数:malloc(),free(),calloc(),
     这些函数声明放在stdlib.h头文件中
     */
    /*
     malloc 函数
       该函数用于跟系统申请一块内存,这块内存的大小由参数决定,而参数的单位为字节(Byte).然后将申请后的内存起始地址返回,我们就可以使用我们的指针变量来接收这个地址,我们建议将这个地址强制转换为对应的指针类型.
     */
    int *p1 = (int *)malloc(sizeof(int));
    
    //申请一个占100个float变量的内存空间
    float *p2 = (float *)malloc(sizeof(float)*100);
    
    //申请内存空间,需要判断内存与否,如果不成功,就会返回空指针(NULL)
//    if ( p1 != (int *)NULL)
//    {
//        printf("动态内存申请成功\n");
//    }else{
//        printf("动态内存申请失败\n");
//   }
    
   //我们使用malloc函数申请内存后,一旦使用完毕,需要释放内存,否则那块内存就成为垃圾内存.
   //使用free()函数释放内存,它里面有个参数,这个参数就是我们需要释放的内存区域的起始地址
    free(p1);    //释放p1内存
    free(p2);
    
    //在控制台输入几个数,然后对这些数字进行倒序排序
    /*
    int count;
    printf("请输入要输入的数字的个数:\n");
    scanf("%d",&count);
    
    int *p3 = (int *)malloc(sizeof(int)*count);
    if (p3 !=(int *)NULL)
    {
        printf("动态内存申请成功\n");
    }else{
        printf("动态内存申请失败\n");
        return 0;
    }
    printf("请输入%d个数字,空格隔开\n",count);
    for (int i =0; i<count; i++)
    {
        scanf("%d",(p3+i));
    }
    printf("数组原顺序为: \n");
    for (int i =0; i<count; i++)
    {
        printf("%d ",*(p3+i));
    }
    printf("\n");
    
    //使用指针倒序排序
    for (int i = 0; i<count/2; i++)
    {
        int tmp = *(p3+i);
        *(p3+i) = *(p3+count-1-i);
        *(p3+count-1-i) = tmp;
    }
    printf("倒序排序后数组元素的顺序为:\n");
    for (int i = 0; i<count; i++)
    {
        printf("%d ",*(p3+i));
    }
    printf("\n");
    free(p3);
    */
    /*
     calloc()函数
          它有两个参数,一个参数用于输入分配的单元个数,第二个参数用于指定单元大小.如果分配不成功也会返回空指针(NULL).malloc函数分配内存之后,该区域的数值并不初始化为0,如果分配的内存之前被使用过,那么使用malloc()分配之后有可能还保留之前的数据.而calloc()分配完毕后,会将该区域的数值初始化为0
        p176例子
     */
    
    //字符串与指针
    char str[] = "Hello world!";
    
    //指针变量可以指向一个字符数组
    char *p4;
    p4 = str;
    printf("p4 = %s\n",p4);
    
    /*
     注意:
       printf()函数中控制字符串是用%s,代表要打印一个字符串,后面传入的参数需要的是字符数组的名称(其实就是字符数组首元素地址),p4中存放的就是这个字符数组的首元素地址.printf()函数会一直将该字符串打印到结尾,直到遇到末端字符'\0'就结束
     */
     //例子
    char *p5;
    //如果想要存储20个字符,那么它的长度应该是21个字节.因为还有一个末端字符
    
   /* p5 = (char *)malloc(sizeof(char)*21);
    printf("请输入一个字符串,字符控制在20个以内:\n");
    
    char c;
    int countNum = 0;
    while ((c = getchar()) != '\n')
    {
        //输入
        *(p5+countNum) = c;
        countNum++;
    }
    
    *(p5+countNum) = '\0';
    printf("字符串为:%s\n",p5);
    
    //将字符串倒序排序
    char *start = p5;
    char *end = (p5+countNum-1);
    
    for (int i = 0; i<countNum/2; i++)
    {
        int tmp = *(start+i);
        *(start+i) = *(end - i);
        *(end - i) = tmp;
    }
    printf("倒序排序后字符串为:%s\n",p5);
    free(p5);
    */
    
    //如何使用指针处理二维字符数组
    char strings[3][20] = {
        "Hello world!",
        "Hello Coder!",
        "Hello Youths!",
    };
    for (int i = 0; i<3; i++) {
        for (int j = 0; j<20; j++) {
            printf("%c",*(*(strings+i)+j));
        }
        printf("\n");
    }
    char *p6;
    p6 = strings[0];
    for (int i = 0; i<3; i++) {
        printf("%s\n",p6+i*20);
    }
 //   free(p6);
      //不能这样使用,因为free()函数只能释放动态分配的内存空间,不能释放任意的内存.
    
    
    //指针作为函数返回值
    /*
     指针除了可以作为函数参数外,也可以作为函数的返回值
     使用指针,可以返回一个数组,因为数组名就是一个地址,我们可以使用指针来代替
     
     指针作为函数返回值基本形式如下:
       类型标志符 *函数名(参数列表)
       
     上述格式中函数返回指针指向的 "数据类型" 是 "类型标志符" 所标志的类型(int,float,double,char)
     */
    
    int *p7 = getArray();
    for (int i = 0; i<10; i++)
    {
        printf("%d ",*(p7+i));
    }
    printf("\n");
    
    /*指针数组
         指针数组是一个数组,该数组中的每一个元素还是一个指针,而这些指针可以继续指向其他的地址
     
     例如:定义一个指针数组
     int *p[4];
     
     在这里的中括号优先级比 * 号高,先结合p[4],这是一个数组形式,有4个元素,然后再与前面的 * 号结合,表示是指针类型.所以p这个数组中有四个元素,每一个元素都是指向整型的指针.
    */
    //例子1
    int arr1[3][4] = {
        {1,2,3,4},
        {5,6,7,8},
        {9,10,11,12}
    };
    int *p8[3];
    for (int i = 0; i<3; i++)
    {
        p8[i] = arr1[i];
        for (int j = 0; j<4; j++)
        {
            printf("%d ",*(p8[i]+j));
        }
        printf("\n");
    }
    
    //例子2:对指针数组的元素进行排序
    char *bookName[5] = {
        "C Primer Plus",
        "Object-C Basic",
        "Visual C++ 2010",
        "Lear Objeactive-C on the Mac",
        "Bengining iphone5s Development"
     
    };
    //声明和实现一个函数,对指针数组的数据进行输出
    //void printBookName(char *name[],int count);
    
    
    //声明和实现一个函数,对指针数组里的数据的地址指向的数据进行一个冒泡排序,并且顺序是从小到大的.
    //void sortBookName(char *name[],int count);
    
    //最后用void printBookName(char *name[],int count);去重新输出排序后的数组
    
    printf("排序前:\n");
    printBookName( bookName,5);
    
    printf("冒泡排序后:\n");
    sortBookName(bookName,5);
    printBookName( bookName,5);
    
    /*
     数组指针(行指针)
       数组指针是一个指针变量,我们定义出来的指针变量中存放的地址必须是数组的地址才行,其他的数据类型的地址不可以存放在这个指针变量中.
     
     定义代码如下:
       (*p)[4];
    注意:(*p)的括号不能省略,如果省略就成了*p[4],这个是指针数组.我们使用括号提升前面*号优先级,表示*p对应一个4个元素的整型数组.该指针只能指向一个包含4个整型元素的一维数组,不能单独指向数组中的某一元素.如果要赋值,可以使用二维数组的名称为该变量进行赋值.
     
     */
    
    int arr2[][4] = {
        {1,2,3,4},
        {5,6,7,8},
        {9,10,11,12}
    };
    int (*p9)[4];
    p9 = arr2;
    for (int i = 0; i<3; i++)
    {
        for (int j = 0; j<4; j++)
        {
            printf("%d ",*(*(p9+i)+j));
        }
        printf("\n");
    }
    
    /*
     指向指针的指针
         定义一个指针变量,指向一个地址,而这个地址上存储的又是一个指针数据,而该指针数据指向的才是实际的数据.
     
     指针的指针 定义形式:
         int **p;
     */
    int **p10;
    int i1 = 10;
    int *p11;
    p11 = &i1;
    p10 = &p11;
    
    //例子
    char **p12;
    for (int i = 0; i<5; i++)
    {
        p12 = bookName+i;
        printf("%s\n",*p12);
    }
    
    /*
     结构体指针变量
       指针变量指向的是一个结构体.
          结构体指针变量中的值是指向 结构体变量的首地址.
     
     结构体指针变量声明的一般形式:
        struct 结构体名称 *结构体指针变量
     或者
        typedef struct {}结构体体名 *结构体指针变量名(一般使用这种形式)
     
     通过结构体访问结构体变量的成员的一般形式:
     (*结构体指针变量).成员变量
     或者
     结构体指针变量->成员名
     */
    
    Student stu ;   //结构体变量
    Student *pStu;  //结构体指针变量
    
    pStu = &stu;
    stu.num = 1;
    stu.name = "Yong";
    stu.sex = 'M';
    stu.score = 99;
    
    printf("我们使用结构体变量打印信息如下:学号 = %d,姓名 = %s,性别 = %c,分数 = %.2f\n",stu.num,stu.name,stu.sex,stu.score);
    printf("我们使用结构体指针变量打印信息如下:学号 = %d,姓名 = %s,性别 = %c,分数 = %.2f\n",(*pStu).num,(*pStu).name,(*pStu).sex,(*pStu).score);
    printf("我们使用结构体指针变量打印信息如下:学号 = %d,姓名 = %s,性别 = %c,分数 = %.2f\n",pStu->num,pStu->name,pStu->sex,pStu->score);
    
    //结构体指针作为函数参数
    //如果我们要对结构体内成员像上面那样一个一个进行赋值,即费时间又费空间,开销大,程序效率大大降低.那么在这情况下,可以使用结构体指针作为函数参数,以提高程序的效率.
    
    Student student = {1,"Yong",'M',99};
    
    Student *studnett;
    studnett = &student;
    print(studnett);
    
    return 0;
}

int *getArray()
{
    static int array[10] = {1,2,3,4,5,6,7,8,9,10};
    for (int i = 0; i<10; i++)
    {
        array[i] += 10;
    }
    return array;
    //return &array[0];
}

void printBookName(char *name[],int count)
{
    
    for (int i = 0; i<count; i++)
    {
        printf("%s\n",name[i]);
    }
    
}
void sortBookName(char *name[],int count)
{
    //使用冒泡排序
    char *tmp;
    for (int i = 0; i<count-1; i++)
    {
        for (int j = 0; j <count-1-i; j++)
        {
            if (strcmp(name[j], name[j+1])>0)
            {
                //交换地址
                tmp = name[j];
                name[j] = name[j+1];
                name[j+1] = tmp;
                
            }
        }
    }

}

void print(Student *stu)
{
    printf("学号 = %d,姓名 = %s,性别 = %c,分数 = %.2f\n",stu->num,stu->name,stu->sex,stu->score);
    

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值