C/C++学习笔记

结构体

  • 定义结构体变量的几种方法:
  1. 先定义结构体类型,再定义变量名
    struct student {
    	int ...
    	char ...
    	long ...
    };
    struct student stu;
    
  2. 在定义结构体类型的同时,定义变量
    struct student {
    	int ...
    	char ...
    	long ...
    } stu;
    
  3. 直接定义结构体变量(不指定结构体标签)【不推荐】
    struct {
    	int ...
    	char ...
    	long ...
    } stu;
    
  • 用typedef给数据类型定义一个别名

    一般用全大写表示别名

    写法一:

    struct student {
    	...
    };
    typedef struct student STUDENT;
    

    写法二:

    typedef struct student {
    	...
    } STUDENT;
    

    写法三:

    typedef struct {
    	...
    } STUDENT;
    
  • 结构体的特性:

    • 使用成员选择运算符“.”来访问结构体变量
    • 支持同类结构体变量的整体赋值
    • 不能使用==和!=来直接判定两个结构体变量是否相等

枚举类型

是一种基本数据类型(整型、字符型、浮点型、枚举类型)。
应用场合:当某些量仅由有限个整型数据值组成时。

typedef enum weeks {SUN, MON, TUE, WED, THU, FRI, SAT} WEEKS;
enum weeks today;
WEEKS today = MON;  

联合/共用体

  • 将结构体类型声明时的struct改为union即可对联合类型进行声明。
  • 同一内存在每一瞬时只能保存一个成员,起作用的成员是最后一次赋值的成员。
    union sample {
    	short i;
    	char ch;
    	float f;
    };
    

指针

指针和一维数组

数组名a就是数组第一个元素a[0]的地址:&a[0]

&a[i]a + i等价

一位数组元素的等价引用形式:a[i]*(a+i)

  • 指针运算+循环:实现数组元素的访问
    int a[10];
    int *p;
    for (p = a; p < a+10; p++) {
      // 访问数组元素x=*p
    }
    

a+1中的“1”不是1Byte,而是一个数组元素所占的大小。(根据指针变量的即基类型而定,如int型就是4Byte)

a+i 实际为 a+i*sizeof(基类型)

  • 易错
    假设有:
    int a[5] = {5, 6, 7, 8, 9};
    int *p = a;
    
    那么:
    • printf("%d\n", ++(*p));的输出是6

      对*p加1,不改变p的指向

    • printf("%d\n", (*p)++);的输出是5

      对*p加1,不改变p的指向

    • printf("%d\n", *p++);的输出是5

      相当于printf("%d\n", *(p++));,即两步操作:

      1. printf("%d\n", *p);
      2. p++;
        p指向了下一个数组元素

指针和二维数组

  • 对二维数组a[][],a代表二维数组的首地址,即第0行的地址(行地址)

    • a+i代表第i行的地址
    • *(a+i)代表第i行第0列的地址
    • 第i行第j列的元素:a[i][j]=*(*(a+i)+j)
  • 按照行指针访问数组元素:
    假设二维数组a[][]共3列,则定义指针p,其指向的基类型为“int[3]”:

    int (*p)[3];
    p = a;
    

    注意不能写成int *p[3];,否则定义的是指针数组,而非数组指针

  • 二维数组的行指针作为函数参数,形参声明:

    // 这里的列数N必须是个常数!
    void ArrayTest(int (*p)[N], int m, int n);
    
  • 也可以用列指针来访问二维数组元素(类似于用计算一维数组下标的形式来处理)

内存映像

  • 只读存储区(代码区和常量存储区)
  • 静态存储区(存放全局变量和静态变量)
  • 动态存储区:
    • 堆:自上向下(由低地址端向高地址端生长),由程序员自行通过动态内存分配函数申请(生存期由程序员决定)
    • 栈:自下向上(由高地址端向低地址端生长),由编译系统自动分配(生存期由函数决定),存储函数参数值、局部变量等

动态内存分配函数

  • 向系统申请大小为size的地址块:void* malloc(unsigned int size);
    系统找到一块未占用的内存,将其标记为已占用,然后把首地址返回,若申请不成功,则返回NULL。
  • 例:申请一块可存放10个整型变量的内存:malloc(10 * sizeof(int));
    void*型指针不指定其指向哪一种类型,可指向任意类型的变量,是一种通用型或无类型的指针(区分值为NULL的空指针)。使用时,需强转为其他类型。

    如:p = (int*)malloc(n * sizeof(int));

  • 释放内存:void free(void* p);

动态数组

  • 程序运行中动态申请的连续内存空间
  • 长度动态可变
/*
动态数组的创建、增长、打印、释放
*/
#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int *array;
    int length;
} DArray;

DArray create(int);
void grow(DArray*, int);
void print(DArray*);
void release(DArray*);
int main()
{
    int n;
    DArray a;
    scanf("%d", &n);
    a = create(n);  // 创建n长动态数组
    print(&a);
    grow(&a, 2 * n);  // 新输入n个数,扩为2n长动态数组
    print(&a);
    release(&a);  // 释放动态数组
    return 0;
}

// 动态数组的创建
DArray create(int n) {
    DArray a;
    int i;
    a.array = (int *)malloc(sizeof(int) * n);
    if (a.array == NULL) {
        printf("Allocation Error");
        exit(0);
    }
    else {
        a.length = n;
        for (i = 0; i < a.length; i++) {
            scanf("%d", a.array + i);
            // 或等价地写成:
            // scanf("%d", &a.array[i]);
        }
    }
    return a;
}

// 动态数组的增长
void grow(DArray *aPtr, int n) {
    int *p, i;
    p = (int *)malloc(sizeof(int) * n);  // 申请新数组的空间
    if (p == NULL) {
        return;
    }
    else {
        for (i = 0; i < aPtr->length; i++){  // 复制之前的数组元素到新数组里
            p[i] = aPtr->array[i];
        }
        for (i = aPtr->length; i < n; i++) {  // 在新数组中,将新元素添加到旧元素之后
            scanf("%d", &p[i]);
        }
        free(aPtr->array);  // 释放旧数组的空间
        aPtr->array = p;
        aPtr->length = n;
    }
    return;
}

// 动态数组的输出
void print(DArray *p) {
    int i;
    for (i = 0; i < p->length; i++) {
        printf("%d ", p->array[i]);
        // 或等价地写成:
        // printf("%d ", *(p->array + i));
    }
    printf("\n");
    return;
}

// 动态数组的释放
void release(DArray *p) {
    free(p->array);
    return;
}


其他

  • 库函数——exit:
    exit(0):正常运行程序并退出程序。
    exit(1):非正常运行导致退出程序;
  • 库函数——memcpy:
    void *memcpy(void *str1, const void *str2, size_t n)
    从存储区 str2 复制 n 个字节到存储区 str1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值