【问题标题】:Having trouble with the array address in C?C 中的数组地址有问题?
【发布时间】:2023-04-11 01:18:01
【问题描述】:

我创建了一个动态数组名称listProduct,现在我想从文件中读取数据并插入到这个数组中。但是我在解析数组时遇到了一些麻烦,我知道我解析了错误的地址:(但我无法解决这个问题。有人可以帮助我(我花了 3 个小时,但没有用)。谢谢全部

在main()中

int main(int argc, char** argv) {

    struct Product* listProduct = (struct Product*) malloc(sizeof(struct Product) * 1); 
    printf("address of listProduct in main: %d \n", &listProduct);
    int length = 0;
    char fileName[] = "products.txt";
    length = readDataFromFile(&listProduct,length,fileName);    
    
    printf("address of listProduct in main after insert \n: %d \n", &listProduct);
    printf("length in main %d \n", length);
    printf("start for in main \n");
    int i;
    for(i =0; i < length; i++){
        printf("%s \n", listProduct[i].tenSanPham);
    }
        
    printf("end for in main \n");   
    return 0;
}

在 readFile 函数中

int readDataFromFile(struct Product* listProduct,int length, char fileName[]){
    printf("address of listProduct in readData: %d \n", (*listProduct));
    FILE *fp;
   char buff[1024];
    struct Product product;
   fp = fopen(fileName, "r");

   while(fgets(buff, 255, (FILE*)fp) != NULL){
        product = convertStringToProduct(buff);
        printf("IN readData: %s \n", product.tenSanPham);
        insertProduct(product, &(*listProduct), length);
        length++;
   }
    fclose(fp); 
   int i ;
   printf("\n\ncheck value in listProduct after insert\n");
   for(i = 0; i < length; i++){
    printf("IN FOREACH readData: %s \n", listProduct[i].tenSanPham);
   }  
    printf("read done \n");
    return length;
}

在插入函数中

void insertProduct(struct Product product, struct Product** listProduct, int length)
{
    printf("addres of listProduct in insert %d \n", (*listProduct));
    printf("Product In Insert: %s \n", product.tenSanPham);
  *listProduct = (struct Product*) realloc(listProduct, sizeof(struct Product) * (length+1));
  (*listProduct)[length] = product;
  printf("Get product inserted: %s length: %d \n", (*listProduct)[length].tenSanPham, length);
  printf("insert done!\n");
}

控制台:

address of listProduct in main: 6487568
address of listProduct in readData: 6486368
IN readData: FOOD 1
addres of listProduct in insert 1905632
Product In Insert: FOOD 1

--------------------------------
Process exited after 0.5239 seconds with return value 3221226356
Press any key to continue . . .

【问题讨论】:

  • 你重新分配了数组,最初是一个元素,所以它的位置可能会改变。
  • @WeatherVane 我该如何解决这个问题?
  • 您永远不会检查任何错误。很坏的习惯
  • @Stack 你想解决什么问题?
  • &amp;(*listProduct) 是什么?

标签: c pointers


【解决方案1】:

你有很多错误。通过启用编译器警告可以找到其中的一些。编译时使用-Wall -Wextra -pedantic (gcc/clang) 或您的编译器的等效项。

首先,realloc(listProduct, ...) 应该是realloc(*listProduct, ...)

其次,realloc 可以返回与提供的地址不同的地址。这就是insertProduct 采用struct Product** 的原因。这允许它更改调用者的指针。 readDataFromFile 需要做同样的事情。参数必须是struct Product **。地址变了不是问题。

这将顺便修复您当前遇到的一些错误。例如,&amp;(*listProduct) 将变为正确。不过最好写成listProduct

进行上述修复后,listProduct[i].tenSanPham 需要更改为 (*listProduct)[i].tenSanPham

%p 用于指针,而不是%d。而且他们(奇怪地)需要被转换为void* for %p

你不检查reallocfopen是否成功。

固定:

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

struct Product { ... };

typedef struct Product Product;  // So we don't have to use "struct Product" everywhere.

Product convertStringToProduct(const char *s) {
    ...
}

void insertProduct(Product **listProductPtr, size_t *lengthPtr, Product product) {
    printf("[insertProduct] Address of variable in caller: %p\n", (void*)listProductPtr);
    if (*lengthPtr)
        printf("[insertProduct] Address of first product: %p\n", (void*)*listProductPtr);  // Same: &((*listProduct)[0])

    Product *tmp = realloc(*listProductPtr, sizeof(Product) * (*lengthPtr + 1));
    if (!tmp) {
       // ...
    }

    *listProductPtr = tmp;
    (*listProductPtr)[(*lengthPtr)++] = product;

    printf("[insertProduct] Address of variable in caller: %p\n", (void*)listProductPtr);
    if (*lengthPtr)
        printf("[insertProduct] Address of first product: %p\n", (void*)*listProductPtr);  // Same: &((*listProduct)[0])
}

void readDataFromFile(Product **listProductPtr, size_t *lengthPtr, const char *fileName) {
    printf("[readDataFromFile] Address of variable in caller: %p\n", (void*)listProductPtr);
    if (*lengthPtr)
        printf("[readDataFromFile] Address of first product: %p\n", (void*)*listProductPtr);  // Same: &((*listProduct)[0])

    FILE *fp = fopen(fileName, "r");
    if (!fp) {
       // ...
    }

    char buff[1024];
    while (fgets(buff, sizeof(buff), fp)) {
        Product product = convertStringToProduct(buff);
        insertProduct(listProductPtr, lengthPtr, product);
    }

    fclose(fp); 

    printf("[readDataFromFile] Address of variable in caller: %p\n", (void*)listProductPtr);
    if (*lengthPtr)
        printf("[readDataFromFile] Address of first product: %p\n", (void*)*listProductPtr);  // Same: &((*listProduct)[0])
}

int main(void) {
    Product *listProduct = NULL;
    size_t length = 0;

    printf("[main] Address of listProduct variable: %p\n", (void*)&listProduct);
    if (length)
        printf("[main] Address of first product: %p\n", (void*)listProduct);  // Same: &(listProduct[0])

    readDataFromFile(&listProduct, &length, "products.txt");
    
    printf("[main] Address of listProduct variable: %p\n", (void*)&listProduct);
    if (length)
        printf("[main] Address of first product: %p\n", (void*)listProduct);

    for (size_t i=0; i<length; ++i) {
        printf("%s\n", listProduct[i].tenSanPham);
    }
        
    return 0;
}

【讨论】:

  • 已更新。错误比我之前想象的要多得多。
  • 非常感谢您的代码
  • 在阅读您的评论后,我首先有一些更新。我的代码几乎成功了,但是 readDataFromFile 中的数据是重复的
  • check value in listProduct after insert IN FOREACH readData: FOOD 3 IN FOREACH readData: FOOD 3 IN FOREACH readData: FOOD 3 read done address of listProduct in main after insert : 6487568 length in main 3 start for in main FOOD 3 FOOD 3 FOOD 3 end for main
  • 请注意我是如何将“Ptr”添加到一些参数变量中的,这样您就可以更轻松地跟踪添加间接级别的时间。
【解决方案2】:

更新后填写我的代码:

#include <stdio.h>
#include <stdlib.h>
#include<string.h>  
#include <stdbool.h>
struct date{
    int day;
    int month;
    int year;
};

typedef struct date date;

struct Product {
    char* maSanPham;
    char* tenSanPham;
    int soLuong;
    char* donVi;
    struct date ngayNhap;
    bool tinhTrang;
};

typedef struct Product Product;  // So we don't have to use "struct Product" everywhere.


struct date convertStringToDate(char str[]){
    char* token = strtok(str,"-");
    struct date d;
    int i = 0;
    while( token != NULL ) {
      if(i == 0){
        d.day = atoi(token);
        token = strtok(NULL, "-");
      }else if(i == 1){
        d.month = atoi(token);
        token = strtok(NULL, "-");  
      }else if(i == 2){
        d.year = atoi(token);
        token = strtok(NULL, "-");
      }else{
        break;
      }
      i++;
      
   }
    return d;
    
}
bool checkBoolean(char str[]){
    return (strcmp(str,"true") == 0);
}



Product convertStringToProduct(char *str) {
    char* regex = "|";
    char* token = strtok(str,regex);
    
    char* maSanPham;
    char* tenSanPham;
    char* donVi;
    int soLuong;
    char* ngayNhap;
    bool tinhTrang;
    int i  = 0;
    while(true){
        if(i==0){
            maSanPham = token;
        }else if(i == 1){
            tenSanPham = token;
        }else if(i == 2){
            soLuong = atoi(token);
        }else if(i == 3){
            donVi = token;
        }else if(i == 4){
            ngayNhap = token;
        }else if(i == 5){
            tinhTrang = checkBoolean(token);
        }else{
            break;
        }
        i++;
        token = strtok(NULL, "|");
    }
    date fngayNhap = convertStringToDate(ngayNhap);
    Product pro = {maSanPham, tenSanPham, soLuong, donVi, fngayNhap.day, fngayNhap.month, fngayNhap.year, tinhTrang};
    return pro;
}

void insertProduct(Product** listProductPtr, size_t *lengthPtr, Product product) {
    printf("[insertProduct]]INFO: Product Name before insert: %s \n", product.tenSanPham);
    
    printf("[insertProduct] Address of variable in caller: %p\n", (void*)listProductPtr);
    if (*lengthPtr)
        printf("[insertProduct] Address of first product: %p\n", (void*)*listProductPtr);  // Same: &((*listProduct)[0])

    Product *tmp = realloc(*listProductPtr, sizeof(Product) * ( (*lengthPtr) + 1));
    if (!tmp) {
        printf("ERROR__________________realloc failed");
    }

    *listProductPtr = tmp;
    (*listProductPtr)[(*lengthPtr)++] = product;


    printf("[insertProduct] Address of variable in caller: %p\n", (void*)listProductPtr);
    if (*lengthPtr)
        printf("[insertProduct] Address of first product: %p\n", (void*)*listProductPtr);  // Same: &((*listProduct)[0])
}

void readDataFromFile(Product **listProductPtr, size_t *lengthPtr, const char *fileName) {
    printf("[readDataFromFile] Address of variable in caller: %p\n", (void*)listProductPtr);
    if (*lengthPtr)
        printf("[readDataFromFile] Address of first product: %p\n", (void*)*listProductPtr);  // Same: &((*listProduct)[0])

    FILE *fp = fopen(fileName, "r");
    if (fp == NULL) {
       printf("ERROR__________________can not open file");
    }

    volatile char buff[1024];
    Product product;
    while (fgets(buff, sizeof(buff), fp) != NULL) {
        product = convertStringToProduct(buff);
        printf("[readDataFromFile]INFO: Product Name after conver: %s \n", product.tenSanPham);
        insertProduct(listProductPtr, lengthPtr, product);
    }

    fclose(fp); 

    printf("[readDataFromFile] Address of variable in caller: %p\n", (void*)listProductPtr);
    if (*lengthPtr)
        printf("[readDataFromFile] Address of first product: %p\n", (void*)*listProductPtr);  // Same: &((*listProduct)[0])
}

int main(void) {
    Product *listProduct = NULL;
    size_t length = 0;

    printf("[main] Address of listProduct variable: %p\n", (void*)&listProduct);
    if (length)
        printf("[main] Address of first product: %p\n", (void*)listProduct);  // Same: &(listProduct[0])

    const char *fileName = "products.txt";
    readDataFromFile(&listProduct, &length, fileName);    
    
    printf("[main] Address of listProduct variable: %p\n", (void*)&listProduct);
    if (length)
        printf("[main] Address of first product: %p\n", (void*)listProduct);

    size_t i;
    for( i=0; i<length; ++i) {
        printf("%s\n", listProduct[i].tenSanPham);
    }
        
    return 0;
}

【讨论】:

  • 这应该是您问题的答案还是更新?在第一种情况下,请阅读How to Answer,然后改进此答案。其次,请编辑您的问题而不是发布答案。
猜你喜欢
  • 2014-05-21
  • 1970-01-01
  • 2020-08-09
  • 1970-01-01
  • 2020-06-07
  • 1970-01-01
  • 2022-01-15
  • 2016-09-19
  • 1970-01-01
相关资源
最近更新 更多