You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言中如何让start指针始终指向动态分配内存的首个Song结构体?

让我来帮你排查并修复问题,你的代码里有几个关键的指针类型不匹配和逻辑错误,直接导致了start指针读取到垃圾值。我们一步步来解决:

核心问题:函数参数类型不兼容

你在main里调用addSong(&ptr, &nrOfSongs)和showList(&start, nrOfSongs, &ptr)时,传递的是指针的地址(双重指针),但函数声明和定义里却用了单指针参数。这种类型不兼容会让编译器做隐式转换,最终导致程序访问错误的内存地址,出现垃圾值。


步骤1:修正函数声明和参数

首先修改FuncDek.h里的函数声明,匹配实际传递的参数类型:

#ifndef FUNCDEK
#define FUNCDEK
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // 新增,用于字符串处理函数

typedef struct {
    char title[30];
    char artist[30];
    unsigned int year;
} Song;

int menu();
void addSong(Song **ptr, int *nrOfSongs); // 改为双重指针
void showList(Song *start, int nrOfSongs); // 移除多余的ptr参数
#endif

步骤2:修复addSong函数的指针操作与赋值逻辑

原来的addSong里,ptr是值传递,修改的只是局部副本,不会影响main里的ptr指针。改成双重指针后,我们需要解引用操作实际的指针;另外手动循环复制字符串的方式容易引入垃圾值,改用字符串处理函数更安全:

#include "FuncDek.h"
#pragma warning(disable: 4996)

int menu() {
    fflush(stdin);
    int choice = 0;
    printf("Menyval på låtlista\n");
    printf("-------------------------\n");
    printf("1. Lägg till låt \n");
    printf("2. Visa låtlista \n");
    printf("3. Blanda låtlistan \n");
    printf("4. Spara till fil \n");
    printf("0. Avsluta program \n");
    scanf("%d", &choice);
    getchar();
    return choice;
}

void addSong(Song **ptr, int *nrOfSongs) {
    system("cls");
    Song temp;

    // 清除scanf后残留的换行符,避免fgets直接读取空行
    int c;
    while ((c = getchar()) != '\n' && c != EOF);

    printf("Ange låtens namn:\n");
    fgets(temp.title, sizeof(temp.title), stdin);
    // 去掉fgets读入的换行符,避免输出时出现多余空行
    temp.title[strcspn(temp.title, "\n")] = '\0';

    printf("Ange artistens namn:\n");
    fgets(temp.artist, sizeof(temp.artist), stdin);
    temp.artist[strcspn(temp.artist, "\n")] = '\0';

    printf("Ange året låtens släpptes: \n");
    scanf("%d", &temp.year);

    // 获取当前要写入的歌曲位置
    Song *current = *ptr;
    // 安全复制字符串和数据
    strcpy(current->title, temp.title);
    strcpy(current->artist, temp.artist);
    current->year = temp.year;

    // 移动main里的ptr指针到下一个空位置(注意括号优先级)
    (*ptr)++;
    (*nrOfSongs)++;
}

步骤3:修复showList函数的遍历逻辑

原来的循环只执行1次,而且参数传递错误。现在start已经是内存块的首地址,直接遍历所有已添加的歌曲即可:

void showList(Song *start, int nrOfSongs) {
    system("cls");
    printf("Song list\n");
    printf("-----------------------------\n");

    Song *current = start;
    for (int i = 0; i < nrOfSongs; i++) {
        printf("Låt: %s \n", current->title);
        printf("Artist: %s \n", current->artist);
        printf("År: %d \n", current->year);
        printf("-----------------------------\n");
        current++;
    }

    // 空列表提示
    if (nrOfSongs == 0) {
        printf("Inga låtar tillagda än.\n");
    }
    system("pause");
}

步骤4:修正main里的函数调用

更新main里的addSong和showList调用,匹配新的参数:

#include "FuncDek.h"
#include <locale.h>
#include <crtdbg.h>

int main() {
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
    setlocale(LC_ALL, "swedish");

    // 分配5个Song的内存
    Song *ptr = (Song *)malloc(sizeof(Song) * 5);
    // start指向内存块的首地址,永远不变
    Song *start = &(ptr[0]);
    int menuChoice = 0;
    int nrOfSongs = 0;

    do {
        system("cls");
        menuChoice = menu();
        switch (menuChoice) {
            case 1:
                // 检查是否超过内存容量(可选,避免越界)
                if (nrOfSongs >=5) {
                    printf("Låtlista är full, kan inte lägga till fler låtar!\n");
                    system("pause");
                    break;
                }
                addSong(&ptr, &nrOfSongs);
                break;
            case 2:
                showList(start, nrOfSongs);
                break;
            default:
                printf("\nFelaktigt val, försök igen\n");
                system("pause");
                break;
        }
    } while (menuChoice != 0);

    // 释放内存,必须用首地址start
    free(start);
    system("pause");
    return 0;
}

关键说明:start指针的正确性

你初始化Song *start = &(ptr[0]);的方式是完全正确的——ptr一开始指向malloc分配的内存首地址,ptr[0]就是第一个Song结构体,取地址后start会一直指向这个首地址,不会随ptr的移动而改变,完美用于遍历整个列表。

内容的提问来源于stack exchange,提问作者anderssinho

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:25:40