备战计算机二级 C 语言知识点(三)

目录

指针

1. 地址与指针变量的概念,地址运算符与间址运算符。

2. 一维、二维数组和字符串的地址以及指向变量、数组、字符串、函数、结构体的指针变量的 定义。通过指针引用以上各类型数据。

3. 用指针作函数参数。

4. 返回地址值的函数。

5. 指针数组,指向指针的指针。

结构体(即“结构”)与共同体(即“联合”)

1. 用 typedef 说明一个新类型。

2. 结构体和共用体类型数据的定义和成员的引用。

3. 通过结构体构成链表,单向链表的建立,结点数据的输出、删除与插入。


指针

1. 地址与指针变量的概念,地址运算符与间址运算符。

  1. 地址:
    • 地址是指内存中某个位置的唯一标识。
    • 在C语言中,可以使用 & 运算符获取变量的地址,即取地址运算符。例如,&variable 获取变量 variable 的地址。
    • 地址是一个无符号整数值,通常以十六进制表示。

示例代码:

#include <stdio.h>

int main() {
    int num = 10;
    float pi = 3.14159;
    char ch = 'A';

    printf("Address of num: %p\n", &num);
    printf("Address of pi: %p\n", &pi);
    printf("Address of ch: %p\n", &ch);

    return 0;
}

输出结果:

Address of num: 0x7ffd3993a12c
Address of pi: 0x7ffd3993a130
Address of ch: 0x7ffd3993a131

在上述示例中,我们使用 & 运算符获取变量 numpich 的地址,并使用 %p 格式说明符打印地址。

  1. 指针变量:
    • 指针是一个存储了内存地址的变量。
    • 在C语言中,可以使用指针来间接访问和操作内存中的数据。
    • 声明指针变量时,需要指定指针所指向的数据类型。例如,int* ptr; 声明了一个指向整数的指针变量。
    • 使用 * 运算符可以访问指针所指向地址的值,即间接寻址运算符。

示例代码:

#include <stdio.h>

int main() {
    int num = 10;
    int* ptr = &num;

    printf("Value of num: %d\n", num);
    printf("Address of num: %p\n", &num);
    printf("Value of ptr: %p\n", ptr);
    printf("Value at address stored in ptr: %d\n", *ptr);

    return 0;
}

输出结果:

Value of num: 10
Address of num: 0x7ffd3993a12c
Value of ptr: 0x7ffd3993a12c
Value at address stored in ptr: 10

在上述示例中,我们声明了一个整型指针变量 ptr,并将其初始化为变量 num 的地址。通过 *ptr,我们可以访问指针 ptr 所指向地址的值。

地址运算符 & 取得变量的地址,而间址运算符 * 则用于访问指针所指向的地址的值。这两个运算符是在处理指针和内存操作时非常常用的工具。

2. 一维、二维数组和字符串的地址以及指向变量、数组、字符串、函数、结构体的指针变量的 定义。通过指针引用以上各类型数据。

  1. 一维数组和字符串的地址:
    • 一维数组是在内存中连续存储的相同类型元素的集合。
    • 字符串是由字符组成的一维字符数组,以空字符 \0 结尾。
    • 一维数组和字符串名本身就代表了它们的起始地址。

示例代码:

#include <stdio.h>

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    char str[] = "Hello";

    printf("Address of arr: %p\n", arr);
    printf("Address of str: %p\n", str);

    return 0;
}

输出结果:

Address of arr: 0x7ffd3993a120
Address of str: 0x7ffd3993a12c

在上述示例中,我们使用数组名 arr 和字符串名 str 直接打印它们的地址。

  1. 二维数组的地址:
    • 二维数组是由多个一维数组排列组成的矩阵形式的数组。
    • 二维数组的地址表示整个二维数组的起始地址,也就是第一个一维数组的地址。

示例代码:

#include <stdio.h>

int main() {
    int matrix[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};

    printf("Address of matrix: %p\n", matrix);

    return 0;
}

输出结果:

Address of matrix: 0x7ffd3993a120

在上述示例中,我们使用二维数组名 matrix 直接打印它的地址。

  1. 指向变量、数组、字符串、函数、结构体的指针变量的定义:
    • 指针变量用于存储内存地址。
    • 可以使用 * 符号定义指针变量,指定指针所指向的类型。
    • 对于变量和数组,可以使用取地址运算符 & 获取其地址,并将其赋值给指针变量。
    • 对于字符串,直接将字符串名赋值给指针变量即可。
    • 对于函数,可以使用函数名作为指针变量。
    • 对于结构体,可以使用结构体类型加上 * 定义指向结构体的指针变量。

示例代码:

#include <stdio.h>

int main() {
    int num = 10;
    int arr[5] = {1, 2, 3, 4, 5};
    char str[] = "Hello";
    
    // 指向变量的指针
    int *ptr_num = &num;

    // 指向数组的指针
    int *ptr_arr = arr;

    // 指向字符串的指针
    char *ptr_str = str;

    printf("Value of num: %d\n", *ptr_num);
    printf("First element of arr: %d\n", *ptr_arr);
    printf("String: %s\n", ptr_str);

    return 0;
}

输出结果:

Value of num: 10
First element of arr: 1
String: Hello

在上述示例中,我们定义了指向变量 num、数组 arr 和字符串 str 的指针变量 ptr_numptr_arrptr_str。通过解引用操作符 * 可以访问这些指针所指向的数据。

以上是指针引用不同类型的数据的示例。可以通过指针来访问和修改变量、数组、字符串的值,以及调用函数和操作结构体。指针的灵活性使得在C语言中可以进行复杂的内存操作和数据操作。

3. 用指针作函数参数。

在C语言中,可以使用指针作为函数参数,以便在函数内部对传入的变量进行修改或操作。这样可以实现通过引用传递(Pass by Reference),而不仅仅是值传递(Pass by Value)。以下是使用指针作为函数参数的示例:

#include <stdio.h>

// 函数通过指针修改变量的值
void modifyValue(int* ptr) {
    *ptr = 100;
}

// 函数通过指针交换两个变量的值
void swap(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main() {
    int num = 5;
    printf("Before modifyValue: %d\n", num);

    // 通过指针修改变量的值
    modifyValue(&num);
    printf("After modifyValue: %d\n", num);

    int a = 10, b = 20;
    printf("Before swap: a = %d, b = %d\n", a, b);

    // 通过指针交换两个变量的值
    swap(&a, &b);
    printf("After swap: a = %d, b = %d\n", a, b);

    return 0;
}

输出结果:

Before modifyValue: 5
After modifyValue: 100
Before swap: a = 10, b = 20
After swap: a = 20, b = 10

4. 返回地址值的函数。

在C语言中,可以编写返回地址值的函数,使函数返回值为一个指针,指向某个内存地址。这样可以将函数内部计算或创建的数据结构通过指针返回给调用者使用。以下是一个返回地址值的函数示例:

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

// 返回动态分配内存的数组的地址
int* createArray(int size) {
    int* arr = (int*)malloc(size * sizeof(int));

    // 假设对数组进行初始化
    for (int i = 0; i < size; i++) {
        arr[i] = i + 1;
    }

    return arr;
}

int main() {
    int size = 5;
    int* ptr = createArray(size);

    printf("Array elements: ");
    for (int i = 0; i < size; i++) {
        printf("%d ", ptr[i]);
    }
    printf("\n");

    free(ptr); // 释放动态分配的内存

    return 0;
}

输出结果:

Array elements: 1 2 3 4 5

在上述示例中,我们定义了一个名为 createArray 的函数,它接受一个参数 size 来指定要创建的数组大小。函数内部使用 malloc 动态分配了一块内存来存储整数数组,并进行了初始化。然后,函数返回这块内存的地址。

main 函数中,我们调用 createArray 函数,并将返回的地址赋值给指针变量 ptr。通过该指针变量,我们可以访问并打印函数内部创建的数组。

需要注意的是,由于动态分配的内存使用完后需要手动释放,我们在程序结束前调用了 free 函数来释放通过 malloc 分配的内存。这是为了避免内存泄漏问题。

通过返回地址值的函数,我们可以方便地将动态创建的数据结构传递给调用者,并且可以灵活地在函数内部进行数据的计算和处理。

5. 指针数组,指向指针的指针。

指针数组和指向指针的指针是C语言中非常有用的概念。

指针数组是一个数组,其元素都是指针。每个指针可以指向不同的数据或对象。可以使用指针数组来管理一组相关的指针。

指向指针的指针是指一个指针变量存储了另一个指针变量的地址。通过指向指针的指针,可以间接访问指针所指向的数据或对象。

以下是指针数组和指向指针的指针的示例:

#include <stdio.h>

int main() {
    int num1 = 10, num2 = 20, num3 = 30;
    int* ptr1 = &num1;
    int* ptr2 = &num2;
    int* ptr3 = &num3;

    // 定义指针数组
    int* ptrArr[] = {ptr1, ptr2, ptr3};
    int i;

    // 通过指针数组访问不同的指针和对应的值
    for (i = 0; i < 3; i++) {
        printf("Value at index %d: %d\n", i, *ptrArr[i]);
    }

    // 定义指向指针的指针
    int** doublePtr = &ptr1;

    // 通过指向指针的指针访问指针和对应的值
    printf("Value pointed by doublePtr: %d\n", **doublePtr);

    return 0;
}

输出结果:

Value at index 0: 10
Value at index 1: 20
Value at index 2: 30
Value pointed by doublePtr: 10

在上述示例中,我们定义了三个整型变量 num1num2num3,以及对应的指针 ptr1ptr2ptr3。这些指针存储着相应变量的内存地址。

然后,我们定义了一个指针数组 ptrArr,其中的元素分别指向 ptr1ptr2ptr3。通过指针数组,我们可以访问每个指针,并使用解引用操作符 * 来获取所指向的值。

接下来,我们定义了一个指向指针的指针 doublePtr,它存储了 ptr1 的地址。通过指向指针的指针,我们可以间接访问 ptr1 和它所指向的值。

指针数组和指向指针的指针可以在许多情况下很有用,例如在函数中传递多个指针或者处理复杂的数据结构。使用这些概念,可以更加灵活地管理和操作内存中的数据。

结构体(即“结构”)与共同体(即“联合”)

1. 用 typedef 说明一个新类型。

在C语言中,可以使用typedef关键字为现有类型定义一个新的类型名称。这样做的好处是可以增强代码的可读性和可维护性。以下是使用typedef定义新类型的示例:

#include <stdio.h>

typedef int Age;  // 为int类型定义一个新类型Age

int main() {
    Age myAge = 25;
    printf("My age is: %d\n", myAge);

    return 0;
}

输出结果:

My age is: 25

在上述示例中,我们使用typedef关键字将int类型定义为一个新的类型Age。然后,我们在main函数中使用Age类型来声明一个变量myAge,并给它赋值为25。最后,我们打印出myAge的值。

通过使用typedef,我们可以为任何现有的类型创建一个新的别名,并使用这个别名来代替原有的类型名称。这样使得代码更加易读、直观,并且方便在需要时对类型进行修改和管理。

2. 结构体和共用体类型数据的定义和成员的引用。

在C语言中,结构体(struct)和共用体(union)是用于定义自定义的复合数据类型的关键工具。

  1. 结构体(struct)是一种可以存储多个不同类型的数据成员的数据类型。通过定义结构体,可以将相关的数据组织在一起,形成一个更复杂的数据结构。以下是结构体的定义和成员引用的示例:
    #include <stdio.h>
    
    // 定义一个struct结构体类型
    typedef struct {
        int age;
        char name[20];
    } Person;
    
    int main() {
        // 声明一个Person类型的结构体变量
        Person person1;
    
        // 设置结构体成员的值
        person1.age = 25;
        strcpy(person1.name, "John");
    
        // 访问结构体成员的值
        printf("Name: %s\n", person1.name);
        printf("Age: %d\n", person1.age);
    
        return 0;
    }
    

    输出结果:

    Name: John
    Age: 25
    

    在上述示例中,我们使用typedef为结构体定义了一个新的名称Person,该结构体包含一个int类型的age成员和一个char数组类型的name成员。

    main函数中,我们声明了一个Person类型的结构体变量person1,然后通过成员运算符.设置和访问结构体成员的值。

  2. 共用体(union)是一种特殊的数据类型,它允许以相同的内存位置存储不同类型的数据。共用体中的数据成员共享同一块内存,只能同时存储其中的一个成员的值。以下是共用体的定义和成员引用的示例:
    #include <stdio.h>
    
    // 定义一个union共用体类型
    typedef union {
        int intValue;
        float floatValue;
        char stringValue[20];
    } Data;
    
    int main() {
        // 声明一个Data类型的共用体变量
        Data data;
    
        // 设置共用体成员的值
        data.intValue = 10;
        printf("intValue: %d\n", data.intValue);
    
        data.floatValue = 3.14;
        printf("floatValue: %.2f\n", data.floatValue);
    
        strcpy(data.stringValue, "Hello");
        printf("stringValue: %s\n", data.stringValue);
    
        return 0;
    }
    

    输出结果:

    intValue: 10
    floatValue: 3.14
    stringValue: Hello
    

    在上述示例中,我们使用typedef为共用体定义了一个新的名称Data,该共用体包含一个int类型的intValue成员、一个float类型的floatValue成员和一个char数组类型的stringValue成员。

    main函数中,我们声明了一个Data类型的共用体变量data,然后通过成员运算符.设置和访问共用体成员的值。注意共用体中的数据成员共享同一块内存,改变其中一个成员的值将影响其他成员。

    通过结构体和共用体,我们可以定义自己的复合数据类型,并灵活地存储和操作不同类型的数据。这样能够更好地组织和管理程序中的数据。

3. 通过结构体构成链表,单向链表的建立,结点数据的输出、删除与插入。

通过结构体构成链表,可以实现单向链表的建立、结点数据的输出、删除和插入等操作。下面是一个示例代码:

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

// 定义链表节点的结构体
typedef struct Node {
    int data;
    struct Node* next;
} Node;

// 在链表末尾插入节点
void insertNode(Node** head, int value) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->data = value;
    newNode->next = NULL;

    if (*head == NULL) {
        // 空链表,将新节点作为头节点
        *head = newNode;
    } else {
        // 非空链表,遍历到链表末尾再插入新节点
        Node* current = *head;
        while (current->next != NULL) {
            current = current->next;
        }
        current->next = newNode;
    }
}

// 删除指定数值的节点
void deleteNode(Node** head, int value) {
    Node* temp = *head;
    Node* prev = NULL;

    // 遍历链表,找到要删除的节点
    while (temp != NULL && temp->data != value) {
        prev = temp;
        temp = temp->next;
    }

    if (temp == NULL) {
        // 未找到要删除的节点
        printf("Node with value %d not found.\n", value);
        return;
    }

    if (prev == NULL) {
        // 删除头节点
        *head = temp->next;
    } else {
        // 删除中间或尾部节点
        prev->next = temp->next;
    }

    free(temp);
}

// 输出链表中的数据
void printList(Node* head) {
    Node* current = head;

    if (current == NULL) {
        printf("Linked list is empty.\n");
        return;
    }

    while (current != NULL) {
        printf("%d ", current->data);
        current = current->next;
    }
    printf("\n");
}

int main() {
    Node* linkedList = NULL;

    // 在链表末尾插入节点
    insertNode(&linkedList, 10);
    insertNode(&linkedList, 20);
    insertNode(&linkedList, 30);
    insertNode(&linkedList, 40);

    // 输出链表数据
    printf("Linked list: ");
    printList(linkedList);

    // 删除节点
    deleteNode(&linkedList, 20);

    // 输出链表数据
    printf("Linked list after deletion: ");
    printList(linkedList);

    return 0;
}

输出结果:

Linked list: 10 20 30 40
Linked list after deletion: 10 30 40

在上述示例中,我们定义了一个单向链表的节点结构体 Node,其中包含数据成员 data 和指向下一个节点的指针 next

通过调用 insertNode 函数,可以在链表末尾插入新的节点。函数会根据链表是否为空进行不同的操作,将新节点插入链表。

通过调用 deleteNode 函数,可以删除链表中指定数值的节点。函数会遍历链表找到要删除的节点,然后进行删除操作。如果链表中不存在要删除的节点,则会输出相应的错误信息。

调用 printList 函数可以输出链表中的数据。函数会遍历链表,依次输出每个节点的数据。

main 函数中,我们首先创建一个空链表 linkedList。然后使用 insertNode 函数插入节点,并使用 printList 函数输出链表数据。接着调用 deleteNode 函数删除一个节点,并再次使用 printList 函数输出链表更新后的数据。

通过以上操作,可以实现单向链表的建立、节点数据的输出、删除和插入等功能。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

善程序员文

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值