文档章节

黑马程序员-4-C语言学习(复杂数据类型)

 明天过后1
发布于 2014/09/29 15:46
字数 3087
阅读 46
收藏 2
点赞 0
评论 0

---------------------- Java培训.Net培训Android培训IOS培训、期待与您交流! ----------------------

1. 数组

    a. 简介

        (1) 数组是一种存放数据的集合,它的存储空间跟元素的个数有关

        (2) 数组特点 :

            1) 元素是有序的

            2) 所有元素都是相同类型的

            3) 数组名是数组的首地址,也是第一个元素的首地址

#include <stdio.h>

int main(){
    int arr[3] = {1,2,3};
    printf("数组首地址 : %p ,第一个元素首地址 :%p\n" ,arr ,&(arr[0]));
    // 打印结果 : 数组首地址 : 0028FF30 ,第一个元素首地址 :0028FF30 
    system("pause");
    return 0;    
}

    b. 数组使用

// 初始化方式
	int a[3] = {10, 9, 6};
	int a[3] = {10,9};
	int a[] = {11, 7, 6};
	int a[4] = {[1]=11,[0] = 7};
	// 访问数组元素
	printf("第 %d 个元素 : %d\n" ,0 ,a[0]);

    c. 数组内存结构

        

    d. 数组使用注意

    // 合法初始化方式 
    int arr[3] = {1,2,3};
    int a = 3;
    // 编译会报错
    // 因为有可能变量 a 没被初始化 
    // int arr1[a] = {1,2,3}; 
    // 编译通过但可能有风险
    // 如果 a 没被初始化他的值是一个不确定的值,可能为负数 
    int arr1[a]; 
    // 数组的下标从 0 开始,最后一个元素的下标是 元素个数减一
    a[0] = 0;
    // 最后一个元素
    a[2] = 0;
    // 数组越界,非常危险,因为它可能访问了操作系统的一块重要的内存空间,非常危险
    a[3] = 0;

    d. 二维数组

        (1) 概念 : 二维数组是一个特殊的一维数组:它的元素是一维数组。例如int a[2][3]可以看作由一维数组a[0]和一维数组a[1]组成,这两个一维数组都包含了3个int类型的元素

            

        (2) 基本使用

     int a[3][4] = {1,2,3,4,5,6};
     int a[3][4] = {{},{},{}};
     // 数组元素简单访问
     int a[][5] = {3,21,31,2,32,1};
     // 注意错误:
     int a[3][4];
     a[3] = {};


2. 字符串

    a. 简介

        (1) 一个 'p' 是一个字符,简单的字符串 "dog"

        (1) 字符串 : 字符数组,很多个字符组合在一起就是字符串了

        (2) 他具有数组的特点.但字符串通常都有一个隐藏字符作为字符数组的末尾元素 : '\0'

    b. 使用

    // 字符串的初始化
    // 下面等价于 : char a [] = {'1','2','3','\0'};
    char a[] = “123”;
    // 不合格的字符串,只能是字符数组  
    // 打印后面会显示乱码                                                          
    // char a [] = {‘1’,’2’,’3’};
    // 字符串的输出”%s”,’\0’是不会输出的
    printf("%s\n" ,a);    // 123

    c. 内存结构

        


1. 指针

    a. 简介 - 指针的重要性

        指针是C语言的精华,它是用来存放变量的地址的,而且我们可以通过指针来直接操作变量,因此学好指针对以后C语言的深入研究有很大的帮助。

    b. 指针的简单使用 

    #include <stdio.h>
    int main(){
        int a = 10;
        int *p; // 定义一个指针变量
        p = &a; // 指针变量保存 a 的内存地址
        printf("%d\n",*p); // 通过内存地址访问变量 *代表取出该地址中存储的内容
        
        p = 0;
        p = NULL; // 清空指针操作
        return 0;
    }

    

    c. 指针变量所占用的存储空间

            1) 指针变量用来存储的是变量的地址,那么在64位编译系统中表示一个内存地址用的是64位二进制数,那么存储该二进制数必须要有8byte的内存空间,因此指针变量的大小为8个字节

            2) 指针变量的大小与其类型无关

    #include <stdio.h>
    int main(){
        int a = 10; // int 类型为4个字节
        int *p = &a; 
        
        long b = 10; //long 类型为8个字节
        long *p2 = &b;
        
        printf("int 类型 指针变量的大小为 : %ld\n", sizeof p); // 64位编译器打印结果为8
        
        printf("long 类型 指针变量的大小为 : %ld\n", sizeof p2); // 64位编译器打印结果为8
        return 0;
    }

    d. 为何指针变量要分类型?

            既然知道指针是用来保存变量的内存地址,那么在访问变量的时候是如何取出地址中的内容呢?其实指针变量的类型就告诉指针一次访问要取出该内存地址开始多少个字节

    #include <stdio.h>
    int main(){
        int a = 10; // int 类型为4个字节  a 的地址: 0x7fff5fbff918 , 指针所存储的地址: 0x7fff5fbff918
        long b = 10; //long 类型为8个字节  b 的地址: 0x7fff5fbff910 , 指针所存储的地址: 0x7fff5fbff910
        /*
            按照内存寻址的原则我们可以知道a的地址比b的地址多4个字节 = 8位
        */
        
        int *p = &a; 
        long *p2 = &b;
        
        printf("a 的地址: %p , 指针所存储的地址: %p\n",&a,p);
        
        printf("b 的地址: %p , 指针所存储的地址: %p\n",&b,p2);
        
        printf("int类型指针一次访问所取出内容大小为 : %ld\n", sizeof *p); // int类型指针一次访问所取出内容大小为 : 4
        
        printf("long 类型指针一次访问所取出内容大小为 : %ld\n", sizeof *p2); // long 类型指针一次访问所取出内容大小为 : 8 
        return 0;
    }

    e. 指针和数组

        在数组中规定 : 数组名是指向该数组的首地址,那么数组名就相当于一个指针,因此我们完全可以使用指针来遍历访问数组各个元素。

    #include <stdio.h>
    int main(){
        int array[5] = {1,2,3,4,5};
        int *p = array;
        for (int i =0 ; i < 5 ; i++){
            printf("array[%d] = %d \n",i,*(p+i)); // *(p+i) 先取出对应位置地址再访问
        }
        return 0;
    }
    /* 打印结果 : 
        array[0] = 1 
        array[1] = 2 
        array[2] = 3 
        array[3] = 4 
        array[4] = 5 
    */

    f. 指针与字符串

            字符串本质为字符数组,那么使用指针来访问字符串跟数组相似,不过访问字符串要注意字符串的结束标志和长度防止访问了一块不可用的内存。

    #include <stdio.h>
    #include <string.h>
    int main(){
        char str[] = {'h','e','l','l','o','\0'};   // 等价于 char str[] = "hello";
        int len = strlen(str);
        char *p = str;
        for(int i = 0; i< len ; i++){
            // printf("str[%d] == %c",i,*(p+i));
            printf("str[%d] == %c\n",i,p[i]); // 等价于 printf("str[%d] == %c\n",i,*(p+i));
        }
        return 0;
    }

            使用指针访问字符串常量 : 

    #include <stdio.h>
    #include <string.h>
    /*
        字符串常量与字符串变量区别:
        字符串常量的指针指向的是常量区的内存空间
        字符串变量指向的是栈中分配的内存地址
    */
    int main(){
        //char str[] = {'h','e','l','l','o','\0'};   // 等价于 char str[] = "hello";
        char * str ="hello";
        int len = strlen(str);
        char *p = str;
        int i;
        for(i = 0; i< len ; i++){
            // printf("str[%d] == %c",i,*(p+i));
            printf("str[%d] == %c ,address : %p\n",i,p[i],(p+i));
        }
        system("pause");
        return 0;
    }


    g. 指针和函数指针

        (1) 函数作为一段程序,在内存中也要占据部分存储空间,它也有一个起始地址,即函数的入口地址。函数有自己的地址,那就好办了,我们的指针变量就是用来存储地址的。因此,可以利用一个指针指向一个函数。其中,函数名就代表着函数的地址。

           (2) 指向函数的指针的定义

                    定义的一般形式:函数的返回值类型 (*指针变量名)(形参1, 形参2, ...);

           (3) 指向函数的指针变量主要有两个用途:

                    调用函数

                    将函数作为参数在函数间传递

        #include <stdio.h>
        typedef int (*sum)(int,int);
        void test(sum s,int a,int b){
            int result = s(a,b); //利用函数指针调用函数 打印结果 : 1 + 1 = 2
            printf("%d + %d = %d",a,b,result);
        }
        int add(int a,int b){
            return a+b;
        }
        int main(){
            sum s = add; // 定义一个函数指针
            test(s,1,1);    //把函数指针作为参数传递
            return 0;
        }


 2. 结构体

    a. 结构体简介和简单使用

        (1) 我们知道当多个相同类型的数据整合在一起可以用数组来表示,但如果对于多种不同类型的数据组合成一个整体这时候我们就需要用到C语言提供的结构体来表示。

        (2) 实际开发中,多种类型的数据组合在一起来表示一种新的数据,这个需求非常多。如表示一个学生的信息有 : 姓名 ,年龄 ,身高 ,体重等。

    #include <iostream>
    typedef struct {
        char *name;
        int age;
        double height;
        int weight; 
    } Student;
    
    /*
    如果不用typedef应该这样写
    声明 :
    struct Student{
        char *name;
        int age;
        double height;
        int weight; 
    };
    定义 : 
    struct Student s = {"Mike" ,22 ,175.5 ,50};
    或者 :
    struct {
        char *name;
        int age;
        double height;
        int weight;
    } stu;
    stu.name = "Mike";
    stu.age = 22;
    stu.height = 175.5;
    stu.weight = 50;
    
    */
    
    int main(){
        Student s = {"Mike" ,22 ,175.5 ,50}; 
        printf("name : %s" ,s.name);
        printf("age : %d" ,s.age);
        printf("height : %f" ,s.height);
        printf("weight : %d" ,s.weight);
        return 0;
    }

    b. 结构体使用注意

        (1) 结构体不能递归定义 : 

    // 错误写法
    struct Student {
        char *name;
        struct Student stu;
    };

        (2) 结构体内可以包含其他结构体 : 

    struct Date{
        int year;
        int month;
        int day;
    };
    struct Student {
        char *name;
        struct Date birthday;
    };

        (3) 结构体只有在定义的时候才会分配存储空间,分配存储空间的原则符合对其算法 :

    /*
        对于结构体的对齐算法 :
            在定义变量的时候会依据结构体占用内存最大的成员为单位为结构体变量分配存储空间
    */
    #include <stdio.h>
    // 声明结构体,不会分配存储空间
    typedef struct {
        char *name; // 64位编译器 : 占用内存8byte
        int age; // 4byte
    } Student;
    
    int main (){
        Student s = {"Mike" ,22}; //定义结构体变量会分配存储空间
        printf("size is : %ld\n",sizeof s); // size is : 8 ,符合对齐算法
        return 0;
    }

        (4) 结构体初始化问题 :

    #include <stdio.h>
    typedef struct {
        char *name; // 64位编译器 : 占用内存8byte
        int age; // 4byte
    } Student;
    
    int main(){
        Student s = {"Mike" ,22};    // 对于这种初始化方式{..}只适用声明变量的时候
        // s = {"Mike" ,22}; // 错误写法
        return 0;
    }

        (5) 相同类型的结构体可以进行赋值:

     #include <stdio.h>
    typedef struct {
        char *name; // 64位编译器 : 占用内存8byte
        int age; // 4byte
    } Student;
    
    int main(){
        Student s = {"Mike" ,22};    // 对于这种初始化方式{..}只适用声明变量的时候
        Student s2 = s;
        printf("name is : %s ,age is : %d\n",s2.name,s2.age); // name is : Mike ,age is : 22
        return 0;
    }

        (6) 结构体指针适用注意 :

   /*
        结构体指针变量的定义形式:struct 结构体名称 *指针变量名
        有了指向结构体的指针,那么就有3种访问结构体成员的方式
        结构体变量名.成员名
        (*指针变量名).成员名
        指针变量名->成员名 
    */
    #include <stdio.h>
     typedef struct {
        char *name; // 64位编译器 : 占用内存8byte
        int age; // 4byte
    } Student;
    
    int main(){   
        Student *s;
        Student s1 = {"Mike" ,22};
        s = &s1;

        printf("name is : %s ,age is : %d\n",s->name,s->age); // name is : Mike ,age is : 22
        printf("name is : %s ,age is : %d\n",(*s).name,(*s).age); // name is : Mike ,age is : 22
        system("pause");
        return 0;
    }


3. 枚举

    a. 简介

         枚举是C语言中的一种基本数据类型,并不是构造类型,它可以用于声明一组常数。当一个变量有几个固定的可能取值时,可以将这个变量定义为枚举类型。比如,你可以用一个枚举类型的变量来表示季节,因为季节只有4种可能的取值:春天、夏天、秋天、冬天。 

    b. 使用

    //  一般形式为:enum 枚举名 {枚举元素1,枚举元素2,……}; 
    // 下面方式均等价
    // (1)
    // 定义枚举类型
    enum WeedDay {Monday,Tuesday,Wednesday,Thursday,Friday,Saturary,Sunday};
    // 定义枚举变量
    enum WeedDay day;
    // (2)
    enum WeedDay {Monday,Tuesday,Wednesday,Thursday,Friday,Saturary,Sunday} day;
    // (3)
    enum {Monday,Tuesday,Wednesday,Thursday,Friday,Saturary,Sunday} day;

    c. 使用注意

    // (1) C语言编译器会将枚举元素{Monday,Tuesday,Wednesday,Thursday,Friday,Saturary,Sunday}作为整型常量处,因此叫枚举常量
    // (2) 枚举元素的值取决于定义时各枚举元素排列的先后顺序。默认情况下,第一个枚举元素的值为0,第二个为1,依次顺序加1。
    //   默认        0       1        2        3        4    5        6    
    enum WeedDay {Monday,Tuesday,Wednesday,Thursday,Friday,Saturary,Sunday};
    
    // (3) 也可以在定义枚举类型时改变枚举元素的值,如果定义了某个值后面的值会依次递增
    //               0       1        2        4          5      6        7    
    enum WeedDay {Monday,Tuesday,Wednesday,Thursday = 4,Friday,Saturary,Sunday};
    
    // (4) 枚举遍历
    // 定义枚举变量
    enum {Monday,Tuesday,Wednesday,Thursday,Friday,Saturary,Sunday} day;
    // 给变量赋值
    day = Monday;
    // 遍历枚举元素
    for (day = Tuesday; day <= Sunday; day++){
        printf("枚举元素 : %d \n",day);
    }










---------------------- Java培训.Net培训Android培训IOS培训、期待与您交流! ---------------------- 

 详情请查看:http://edu.csdn.net/heima



© 著作权归作者所有

共有 人打赏支持
粉丝 2
博文 20
码字总数 36166
作品 0
佛山
C语言编程新手基础学习:Windows编程入门

C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到...

小辰带你看世界 ⋅ 05/22 ⋅ 0

C语言再学习--关键字

C语言一共有32个关键字,如下表所示: 关键字 说明 auto 声明自动变量 short 声明短整型变量或函数 int 声明整型变量或函数 long 声明长整型变量或函数 float 声明浮点型变量或函数 double 声...

qq_29350001 ⋅ 2016/11/03 ⋅ 0

2014年IT毕业生——年终总结与生存调查报告

从事IT行业的比例及薪资对比 2014年,近百万IT相关毕业生就业情况如何,都从事什么行业呢?据麦克斯2014年IT专业毕业生从业调查数据显示,仅有约45%的毕业生找到IT相关工作,那其余毕业生都从...

郭奕峰 ⋅ 2015/03/04 ⋅ 0

一个资深C语言工程师说如何学习C语言

谈及C语言,我想C语言功能强大都应该知道、应用广泛,一旦掌握了后,你就可以理直气壮地对他人说“我是电脑高手!”,而且以后若是再自学其他语言就显得轻而易举了。忧虑的是,C语言般博大精...

小辰GG ⋅ 2017/12/16 ⋅ 0

一、C语言概述

说明:这个C语言专题,是学习iOS开发的前奏。也为了让有面向对象语言开发经验的程序员,能够快速上手C语言。如果你还没有编程经验,或者对C语言、iOS开发不感兴趣,请忽略 为什么iOS开发要先...

长平狐 ⋅ 2013/03/28 ⋅ 1

一个新手小白是怎么安排如何自学C语言/C++程序员、工程师的

谈及C语言,我想C语言功能强大都应该知道、应用广泛,一旦掌握了后,你就可以理直气壮地对他人说“我是电脑高手!”,而且以后若是再自学其他语言就显得轻而易举了。忧虑的是,C语言般博大精...

小辰带你看世界 ⋅ 2017/12/31 ⋅ 0

黑马程序员_集合(上)

---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity开发</a>、<a href="http://www.itheima.com"target="blank">.Net培训</a>、期待与您交流! --------......

072 ⋅ 2014/07/10 ⋅ 0

【备忘】2017年黑马【淘宝店铺装修实战操作视频】全套无加密

2017年黑马【淘宝店铺装修实战操作视频】全套无加密 简介: 淘宝装修,对于一个好的店铺来讲,是至关重要的,因为客户只能从网上的文字和图片来了解您,了解产品,所以做得好能增加用户的信任...

qq_38155396 ⋅ 2017/07/01 ⋅ 0

给大家分享黑马程序员Android课程笔记

黑马程序员课程笔记,这套笔记目的是让黑马的学员能够有一个详细的课下资料,也非常适合想学习Android的同学。 这套课程笔记包含内容: 1.Android基础视频部分: 2.Android360项目: 3.智慧北...

小梦想家 ⋅ 2015/12/04 ⋅ 4

PHP基础班学习经历

仿佛昨天还在开学(11月3号),一晃现在已经是23号了,时间就像流水一般匆匆溜走;回顾这大半个月的学习,用两个字来形容的话,那就是——充实; 1.黑马模式 话说回来,黑马的上课教学模式上...

洛根森 ⋅ 2017/11/26 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

linux 安装docker

通过以下命令下载安装docker wget -qO- https://get.docker.com | sh 执行以上命令后输出以下内容说明安装成功,注意红框中的内容,docker安装成功后默认只有root能使用,红框中给出的提示是...

haoyuehong ⋅ 14分钟前 ⋅ 0

482. License Key Formatting - LeetCode

Question 482. License Key Formatting Solution 思路:字符串转化为char数组,从后遍历,如果是大写字母就转化为小写字母,如果是-就忽略,如果遍历了k个字符(排除-)就追加一个-。 Java实现...

yysue ⋅ 32分钟前 ⋅ 0

聊聊spring cloud gateway的LoadBalancerClientFilter

序 本文主要研究一下spring cloud gateway的LoadBalancerClientFilter GatewayLoadBalancerClientAutoConfiguration spring-cloud-gateway-core-2.0.0.RELEASE-sources.jar!/org/springfram......

go4it ⋅ 57分钟前 ⋅ 0

详解:Nginx反代实现Kibana登录认证功能

Kibana 5.5 版后,已不支持认证功能,也就是说,直接打开页面就能管理,想想都不安全,不过官方提供了 X-Pack 认证,但有时间限制。毕竟X-Pack是商业版。 下面我将操作如何使用Nginx反向代理...

问题终结者 ⋅ 今天 ⋅ 0

002、nginx配置虚拟主机

一、nginx配置虚拟主机可分为三种方式,分别为: 1、基于域名的虚拟主机,通过域名来区分虚拟主机——应用:外部网站 2、基于端口的虚拟主机,通过端口来区分虚拟主机——应用:公司内部网站...

北岩 ⋅ 今天 ⋅ 0

shell脚本之死循环写法

最近在学习写shell脚本,在练习if while等流程控制时,突然它们的死循环写法是怎么样的?经过百度与亲测记录如下: for死循环 #! /bin/bashfor ((;;));do date sleep 1d...

hensemlee ⋅ 今天 ⋅ 0

苹果的ARKit2.0有多可怕,看了就知道

序言 ARKit主要由三部分组成: 跟踪(Tracking) 跟踪是ARKit的核心组件之一,其提供了设备在物理世界中的位置与方向信息,并对物体进行跟踪,如人脸。 2.场景理解(Scene Understanding) 场...

_小迷糊 ⋅ 今天 ⋅ 0

5.1 vim介绍 5.2 vim移动光标 5.3 ,5.4vim一般模式下移动光标,复制粘贴

vim命令 vim是vi的一个升级版;vim可以显示文字的颜色 安装vim这一个包vim-enhanced 如果不知道安装包,可以使用 命令下面命令来查看vim命令是那个包安装的。 [root@linux-128 ~]# yum prov...

Linux_老吴 ⋅ 今天 ⋅ 0

vim一般模式

vim 是什么 vim是什么 ? 在之前接触Linux,编辑网卡配置文件的时候我们用过了vi ,vim简单说就是vi的升级版,它跟vi一样是Linux系统中的一个文本编辑工具。 如果系统中没有vim ,需要安装一...

李超小牛子 ⋅ 今天 ⋅ 0

docker实战

构建企业级Docker虚拟化平台实战 重点剖析虚拟化和云计算概念; 分析Docker虚拟化的概念和原理; 从0开始实战Docker虚拟化平台; 基于Docker构建Nginx WEB服务器和CentOS虚拟机; 基于开源监...

寰宇01 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部