C语言 无法使用箭头运算符访问结构成员

rm5edbpk  于 2023-10-16  发布在  其他
关注(0)|答案(3)|浏览(77)

我无法使用箭头操作符打印结构成员的动态分配内存中的数据,但我可以使用相同的箭头操作符将数据放入其中

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

typedef struct {
    int RollNo;
    char Name[15];
    int Class;
    int Marks;
    int Comments[100];
} details;

int main()
{
    int n, i, j;
    printf("Enter number of students\n");
    if (scanf("%d", &n) != 1) {
        perror("Invalid Input");
        return 1;
    }
    details *memptr = malloc(n * sizeof(details));
    if (memptr == NULL) {
        perror("Memory not allocated successfully!!\n");
        return 1;
    }
    for (i = 0; i < n; i++, memptr++) {
        printf("Enter RollNo: ");
        scanf("%d%*c", &(memptr->RollNo));
        printf("Enter Name: ");
        fgets(memptr->Name, 15, stdin);
        printf("Enter Class: " );
        scanf("%d%*c", &(memptr->Class));
        printf("Enter Marks: ");
        scanf("%d%*c", &(memptr->Marks));
        printf("Enter Comments: ");
        fgets(memptr->Comments, 100, stdin);
        printf("\n");
    }

    printf("Student details\n\n");
    for (j = 0; j < n; j++, memptr++) {
        printf("RollNo: %d ", memptr->RollNo);
        printf("Name: %s ", memptr->Name);
        printf("Class: %d ", memptr->Class);
        printf("Marks %d ", memptr->Marks);
        printf("Comments: %s\n", memptr->Comments);
    }

    return 0;
}

为什么我不能用箭头操作符读取动态分配内存中的内容,但我可以用箭头操作符将数据放入其中?

lzfw57am

lzfw57am1#

您正在将指针移动到无效的地址。

for(i=0;i<n;i++,memptr++){
        printf("Enter RollNo: ");
        scanf("%d%*c",&(memptr->RollNo));
        ...
    }

    // Here, memptr points behind the last element of the allocated memory.
    // Any access behind that address is causing undefined behaviour.

    for(j=0;j<n;j++,memptr++){
        printf("RollNo: %d ",memptr->RollNo);
        ...
    }

在调试器中执行程序,并在单步执行代码时观察指针,应该会立即发现这一点。
修改*alloc函数返回的指针从来都不是一个好主意。
使用您的计数器作为索引:

for (i=0; i<n; i++) {
        printf("Enter RollNo: ");
        scanf("%d%*c",&(memptr[j].RollNo));
        ...
    }

    for (j=0; j<n; j++) {
        printf("RollNo: %d ",memptr[j].RollNo);
        ...
    }

您也可以将memptr复制到临时变量并递增该变量。在第一次循环后,必须将该变量重置为初始值memptr
顺便说一句:你也不应该混合使用scanffgets,因为这可能会混淆缓冲。

bakd9h0s

bakd9h0s2#

你增加了指向已分配块的指针,因此你失去了原始值,第二个循环继续增加这个指针,超过已分配数组的末尾。
您应该使用memptr[i].xxx而不是memptr->xxx,并且不再递增指针,或者您应该使用单独的变量作为指针。
还请注意,fgets(memptr->Name, 15, stdin);将在Name数组中存储尾随的换行符,前提是名称短于14个字符,并且如果输入了更长的行,则会在输入流中留下额外的字符。
以下是修改后的版本:

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

typedef struct {
    int RollNo;
    char Name[15];
    int Class;
    int Marks;
    int Comments[100];
} details;

int main()
{
    int n, i, j;
    printf("Enter number of students\n");
    if (scanf("%d", &n) != 1) {
        perror("Invalid Input");
        return 1;
    }
    details *array = malloc(n * sizeof(*array));
    if (array == NULL) {
        perror("Memory not allocated successfully!!\n");
        return 1;
    }
    details *memptr;
    int status = 0;
    for (i = 0, memptr = array; i < n; i++, memptr++) {
        printf("Enter RollNo: ");
        if ((status = scanf("%d", &memptr->RollNo)) != 1)
            break;
        printf("Enter Name: ");
        if ((status = scanf(" %14[^\n]", memptr->Name)) != 1)
            break;
        printf("Enter Class: " );
        if ((status = scanf("%d", &memptr->Class)) != 1)
            break;
        printf("Enter Marks: ");
        if ((status = scanf("%d", &memptr->Marks)) != 1)
            break;
        printf("Enter Comments: ");
        if ((status = scanf(" %99[^\n]", memptr->Comments)) != 1)
            break;
        printf("\n");
    }
    if (status != 1) {
        fprintf(stderr, "Invalid input\n");
        free(array);
        return 1;
    }

    printf("Student details\n\n");
    for (j = 0, memptr = array; j < n; j++, memptr++) {
        printf("RollNo: %d ", memptr->RollNo);
        printf("Name: %s ", memptr->Name);
        printf("Class: %d ", memptr->Class);
        printf("Marks %d ", memptr->Marks);
        printf("Comments: %s\n", memptr->Comments);
    }
    free(array);

    return 0;
}
fivyi3re

fivyi3re3#

你可以分配内存,但不能释放内存。
以下是我的回答:

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

typedef struct Detail {
    int RollNo;
    char Name[100];
    int Class;
    int Marks;
    char Comments[100];
}details;

int main()
{
    int n,i,j,c,name;
    printf("Enter number of students\n");
    if(scanf("%d",&n)!=1){
        perror("Invalid Input");
        return 1;
    }
    details* memptr = malloc(n*sizeof(details));
    if(memptr==NULL){
        perror("Memory not allocated successfully!!\n");
        return 1;
    }

    memset(memptr, 0, n*sizeof(details));

    for(i=0;i<n;i++){
        int m = 0;
        int ak = 0;
        printf("***Total %d student, now first %dth student details\n", n, i+1);
        printf("Enter RollNo: ");
        scanf("%d",&(memptr[i].RollNo));
        fflush(stdin);
        printf("Enter Name: ");
        name = getchar();
        memptr[i].Name[0] = name;
        for(ak = 0;ak < 99; ak++){
            if((name = getchar()) != '\n'){
                memptr[i].Name[ak] = name;
            }else{
                break;
            }
        }
        printf("Enter Class: " );
        scanf("%d",&(memptr[i].Class));
        printf("Enter Marks: ");
        scanf("%d",&(memptr[i].Marks));
        fflush(stdin);
        printf("Enter Comments: ");
        c = getchar();
        memptr[i].Comments[0] = c;
        for(m = 0;m < 99; m++){
            if((c = getchar()) != '\n'){
                memptr[i].Comments[m] = c;
            }else{
                break;
            }
        }

        
        printf("\n");
    }

    printf("Below is student details:\n");
    for(j=0;j<n;j++){
        printf("RollNo: %d ",memptr[j].RollNo);
        printf("Name: %s ",memptr[j].Name);
        printf("Class: %d ",memptr[j].Class);
        printf("Marks %d ",memptr[j].Marks);
        printf("Comments: %s\n",memptr[j].Comments);
    }
    free(memptr);
    memptr = NULL;
    return 0;
}

运行它将输出:

Enter number of students
2
***Total 2 student, now first 1th student details
Enter RollNo: 1
Enter Name: john bob hi
Enter Class: 2
Enter Marks: 23
Enter Comments: He is good!!!

***Total 2 student, now first 2th student details
Enter RollNo: 2
Enter Name: jeff john hek
Enter Class: 1
Enter Marks: 11
Enter Comments: He is very bad!!!

Below is student details:
RollNo: 1 Name: john bob hi Class: 2 Marks 23 Comments: He is good!!!
RollNo: 2 Name: jeff john hek Class: 1 Marks 11 Comments: He is very bad!!!

以下是我的另一个解决方案:

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

#define MAXSTRING 100

typedef struct Detail {
    int RollNo;
    char Name[100];
    int Class;
    int Marks;
    char Comments[100];
}details;

char* get_string(int* stringNum, int* status)
{
    int ak = 0;
    int c = 0;
    char* InputString = malloc(sizeof(char) * MAXSTRING);
    if(InputString == NULL){
        perror("Memory not allocated successfully!!\n");
    *status = 0;
        return NULL;
    }
    memset(InputString, 0, sizeof(char) * MAXSTRING);
    if(*stringNum > 99){
        printf("You want to input string is too long\n");
        *status  = 1;
        return NULL;
    }
    for(ak = 0;ak < MAXSTRING - 1; ak++){
        if((c = getchar()) != '\n'){
            InputString[ak] = c;
        }else{
            break;
        }
    }
    *status  = 2;
    return InputString;

}

int main()
{
    int n,i,j,temp,LengthName = 0, LengthComment = 0, statusNameOK = 0, statusCommentOK = 0;
    char* returnName = NULL;
    char* returnComment = NULL;
    printf("Enter number of students\n");
    if(scanf("%d",&n)!=1){
        perror("Invalid Input");
        return 1;
    }
    details* memptr = malloc(n*sizeof(details));
    if(memptr==NULL){
        perror("Memory not allocated successfully!!\n");
        return 1;
    }

    memset(memptr, 0, n*sizeof(details));

    for(i=0;i<n;i++){
        int m = 0;
        printf("***Total %d student, now first %dth student details\n", n, i+1);
        printf("Enter RollNo: ");
        scanf("%d",&(memptr[i].RollNo));
        fflush(stdin);
        temp = getchar();
        printf("Enter length of Name(max length is 100):");
        scanf("%d",&LengthName);    
        printf("Enter Name: ");
        temp = getchar();
        returnName = get_string(&LengthName, &statusNameOK);
        if(statusNameOK == 0){
            return -1;
        }
        while(returnName == NULL){
            printf("Enter length of Name(max length is 100():");
            scanf("%d",&LengthName);
            printf("Enter Name: ");
            returnName = get_string(&LengthName, &statusNameOK);
        }

        strncpy(memptr[i].Name, returnName, LengthName);
        free(returnName);
        returnName = NULL;

        printf("Enter Class: " );
        scanf("%d",&(memptr[i].Class));
        printf("Enter Marks: ");
        scanf("%d",&(memptr[i].Marks));
        fflush(stdin);
        temp = getchar();

        printf("Enter length of comment(max length is 100):");
        scanf("%d",&LengthComment); 
        printf("Enter comment: ");
        temp = getchar();
        returnComment = get_string(&LengthComment, &statusCommentOK);
        if(statusCommentOK == 0){
            return -1;
        }
        while(returnComment == NULL){
            printf("Enter length of comment(max length is 100():");
            scanf("%d",&LengthComment);
            printf("Enter comment: ");
            returnComment = get_string(&LengthComment, &statusCommentOK);

        }
        strncpy(memptr[i].Comments, returnComment, LengthComment);
        free(returnComment);
        returnComment = NULL;

        printf("\n");
    }

    printf("Below is student details:\n");
    for(j=0;j<n;j++){
        printf("RollNo: %d ",memptr[j].RollNo);
        printf("Name: %s ",memptr[j].Name);
        printf("Class: %d ",memptr[j].Class);
        printf("Marks %d ",memptr[j].Marks);
        printf("Comments: %s\n",memptr[j].Comments);
    }
    free(memptr);
    memptr = NULL;

    return 0;

}

运行它将输出:

Enter number of students
2
***Total 2 student, now first 1th student details
Enter RollNo: 1
Enter length of Name(max length is 100):23
Enter Name: wf dsbdfs fnfg fgsn
Enter Class: 2
Enter Marks: 23
Enter length of comment(max length is 100):45
Enter comment: vdvdfbd  dfbdfsb fgsdb dfbssfdbdfsb dfbfdsbfdsgb

***Total 2 student, now first 2th student details
Enter RollNo: 3
Enter length of Name(max length is 100):34
Enter Name: dvd dbdfb dfgdfgfd dbdfb dfgdfg
Enter Class: 3
Enter Marks: 23
Enter length of comment(max length is 100):67
Enter comment: sdvvdv dsgvds dgdsagdafb!   

Below is student details:
RollNo: 1 Name: wf dsbdfs fnfg fgsn Class: 2 Marks 23 Comments: vdvdfbd  dfbdfsb fgsdb dfbssfdbdfsb dfbfdsbfd
RollNo: 3 Name: dvd dbdfb dfgdfgfd dbdfb dfgdfg Class: 3 Marks 23 Comments: sdvvdv dsgvds dgdsagdafb!

相关问题