การเปลี่ยนแปลงค่าของอาเรย์ของโครงสร้างแบบสุ่ม

ภายในรหัสของฉัน ฉันกำลังอ่านชื่อและหมายเลขโทรศัพท์ของไฟล์และชื่อที่สอดคล้องกับหมายเลขโทรศัพท์ ปัญหาที่ฉันมีในโค้ดของฉันคือหลังจาก for loop ในฟังก์ชันโหลดของฉัน

ปัญหานี้เป็นการสุ่มเปลี่ยนค่าทั้งหมดของชื่อโครงสร้างของฉันไปเป็นชื่อที่ได้รับมอบหมายล่าสุด นอกจากนี้ฉันยังไม่เข้าใจวิธีการแปลงจากโทเค็นแยกเป็นลอยจากสตริงอย่างถ่องแท้

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


struct _data {
     char *name;
     long number;
};

int SCAN(FILE *(*stream)){
     int count;
     char dataString[50];
     int check = 1;
     count = 0;

     while(check){
          fscanf(*stream, "%s\n", dataString);
          fscanf(*stream, "%s\n", dataString);
          if (feof(*stream)){
               check = 0;
          }
          count++;
     }      
     return count;
}

struct _data *LOAD(FILE *stream, int size){
     int x;
     char *tempLine;
     size_t length = 0;
     const char delim[2] = " ";
     char *token;

     rewind(stream);
     struct _data *array = malloc(sizeof(struct _data) * size);  
     printf("this is the size: %d\n\n", size);
     for(x = 0; x < size; x++){
          getline(&tempLine, &length, stream);
          token = strtok(tempLine, delim);
          //printf("this is inside the for loop of load: %s\n", token);
          array[x].name = token;
          token = strtok(tempLine, delim);
          //printf("this is the token: %s\n", token);
          array[x].number = atol(token);
          printf("this is name %s, and phone number %ld\n", array[x].name, array[x].number);
     }
     printf("i am now outside the initial for loop in load\n\n");
     for(x = 0; x < size; x++){
               printf("this is name %s, and phone number %ld\n", array[x].name, array[x].number);
          }
     return array;

}

void SEARCH(struct _data *BlackBox, char *name, int size){
     int x;
     int check = 0;
     for(x = 0; x < size; x++){
          printf("BlackBox Name: %s, check name: %s\n", BlackBox[x].name, name);
          //printf("this is the check: %d\n", strcmp(BlackBox[x].name, name));
          if (0 == strcmp(BlackBox[x].name, name)){
               printf("*******************************************\n");
               printf("The name was found at the %d entry.\n", x);
               printf("*******************************************\n");
               check = 1;  
          }
     }
     if (check == 0){
          printf("*******************************************\n");
          printf("The name was NOT found.\n");
          printf("*******************************************\n");
     }
}

void FREE(struct _data *BlackBox, int size){
     free(BlackBox);
}

int  main(int argv, char **argc){
     FILE *fp;
     int size;
     int x;
     struct _data *BlackBox;
     if(argv < 2){
          printf("*******************************************\n");
          printf("* You must include a name to search for.  *\n");
          printf("*******************************************\n");
     }else{
          fp = fopen("hw5.data", "r");
          size = SCAN(&fp);
          BlackBox = LOAD(fp, size);
         /* for(x = 0; x < size; x++){
               printf("BlackBox Name: %s, check name: %s\n", BlackBox[x].name, argc[1]);
          }*/          
          SEARCH(BlackBox, argc[1], size);
          FREE(BlackBox, size);
     }
     return 0;
}

นี่คือข้อมูลของฉัน

ron 7774013
jon 7774014
tom 7774015
won 7774016
bonny 7774017

นี่คือผลลัพธ์ของฉัน

ron 0
jon 0 
tom 0 
won 0 
bonny 0
i am now outside the initial for loop in load
bonny 0
bonny 0
bonny 0
bonny 0
bonny 0

person Jeffrey Hennen    schedule 18.02.2017    source แหล่งที่มา
comment
array[x].name = token; คัดลอกเฉพาะตัวชี้ของสถานที่ใน tempLine เป็นไปได้ว่าคุณต้องการสำเนาของสตริง   -  person chux - Reinstate Monica    schedule 18.02.2017


คำตอบ (1)


คุณยังคงนำพื้นที่ที่จัดสรรโดย getline() มาใช้ซ้ำ ดังนั้นคุณจะเห็นเฉพาะค่าสุดท้ายเท่านั้น คุณต้องตั้งค่า tempLine เป็น NULL และ length เป็น 0 หลังการวนซ้ำ คุณควรตรวจสอบค่าที่ส่งคืนจาก getline() เพื่อให้แน่ใจว่าคุณมีข้อมูลที่จะอ่านจริงๆ

การเรียก strtok() ครั้งที่สองของคุณควรใช้ตัวชี้ NULL โดยการระบุ tempLine อีกครั้ง คุณกำลังแปลงชื่อเป็นตัวเลข

      getline(&tempLine, &length, stream);
      token = strtok(tempLine, delim);
      //printf("this is inside the for loop of load: %s\n", token);
      array[x].name = token;
      token = strtok(tempLine, delim);
                     ^^^ should be NULL!

คุณควรจะพบปัญหานี้เมื่อคุณพิมพ์โทเค็น

รหัสนี้อาจทำงานได้ตามที่คุณต้องการ แต่ยังไม่ได้คอมไพล์

struct _data *LOAD(FILE *stream, int size)
{
    char *tempLine = NULL;
    size_t length = 0;
    const char delim[] = " ";
    char *token;
    int x;

    rewind(stream);
    struct _data *array = malloc(sizeof(struct _data) * size);
    printf("this is the size: %d\n\n", size);
    for (x = 0; x < size; x++)
    {
        if (getline(&tempLine, &length, stream) == -1)
        {
            free(tempLine);
            break;
        }
        token = strtok(tempLine, delim);
        // printf("this is inside the for loop of load: [%s]\n", token);
        array[x].name = token;
        token = strtok(NULL, delim);
        // printf("this is the token: [%s]\n", token);
        array[x].number = atol(token);
        printf("%d: this is name %s, and phone number %ld\n", x, array[x].name, array[x].number);
        length = 0;
        tempLine = NULL;
    }
    printf("i am now outside the initial for loop in load\n\n");
    for (int i = 0; i < x; i++)
    {
        printf("%d: this is name %s, and phone number %ld\n", i, array[i].name, array[i].number);
    }
    return array;
}

นอกจากนี้ โปรดทราบว่าโดยทั่วไปคุณควรหลีกเลี่ยงการสร้างชื่อที่ขึ้นต้นด้วยขีดล่าง (เช่น struct _data) ชื่อดังกล่าวจำนวนมากถูกสงวนไว้สำหรับการใช้งานโดยการดำเนินการ วิธีที่ง่ายที่สุดในการหลีกเลี่ยงการสร้างชื่อที่ขึ้นต้นด้วยขีดล่างทั้งหมด

person Jonathan Leffler    schedule 18.02.2017
comment
ใช่!!! ได้ผล ขอบคุณ!! แต่ใช่แล้ว ฉันกำลังใช้ฟังก์ชันที่กำหนดไว้ล่วงหน้าจากอาจารย์ของฉัน ดังนั้นนี่คือเหตุผลว่าทำไมฉันถึงมีชื่อแบบนั้น (นั่นคือวิธีที่เขานิยามไว้ในการบ้าน) - person Jeffrey Hennen; 18.02.2017
comment
คุณไม่สามารถช่วยเหลืออาจารย์ที่มีนิสัยการเขียนโค้ดที่ไม่ดีได้ จดบันทึกปัญหา ถามเกี่ยวกับเรื่องนี้ว่าคุณกล้าหรือไม่ และจำไว้สำหรับงานของคุณเอง - person Jonathan Leffler; 18.02.2017
comment
ปัญหาคือเพราะฉันมีชื่อในแต่ละดัชนีที่ตั้งค่าเป็นตัวชี้ ด้วยเหตุนี้มันจึงถูกเปลี่ยนเส้นทางไปยังที่อยู่ของตัวชี้ซึ่งมีค่าสุดท้าย ฉันถูกต้องตามสมมติฐานนี้หรือไม่ - person Jeffrey Hennen; 18.02.2017
comment
ใช่ — โดยพื้นฐานแล้วถูกต้อง หากคุณมีบรรทัดที่ยาวมาก คุณอาจจัดการเพื่อให้ getline() จัดสรรบัฟเฟอร์ที่ยาวขึ้น ซึ่งในกรณีนี้คุณอาจมีค่าสองชุดในอาร์เรย์ของคุณ แต่เกณฑ์มักจะเป็น 256 สำหรับการจัดสรรเริ่มต้น ดังนั้นบรรทัด ก็คงนานพอสมควรแล้วจริงๆ ด้วยการรีเซ็ตความยาวและตัวชี้เป็น NULL ในการวนซ้ำแต่ละครั้ง คุณจะบังคับให้ getline() จัดสรรในการเรียกแต่ละครั้ง การจัดสรรเสร็จสิ้นก่อนที่จะตรวจพบ EOF ดังนั้นการตรวจจับ EOF จำเป็นต้องเพิ่มพื้นที่ว่างที่จัดสรร - person Jonathan Leffler; 18.02.2017
comment
หวานขอบคุณ. คุณช่วยให้ฉันเรียนรู้จริงๆ จริงๆ แล้วเป็นหนึ่งในคนที่มีคำตอบที่ดีกว่าที่ฉันเคยเห็นมา - person Jeffrey Hennen; 18.02.2017
comment
โปรดทราบว่ามีปัญหาร้ายแรงที่ซุ่มซ่อนอยู่ในปีกหากคุณพยายามเพิ่มหน่วยความจำ สมมติว่าผู้ใช้นำหน้าอินพุตด้วยช่องว่าง 2 ช่อง ดังนั้นตัวชี้ที่บันทึกไว้ใน array[x].name จะไม่เป็นตัวชี้ที่ส่งคืนโดย malloc() ดังนั้นการพยายามปล่อยออกจะสร้างความหายนะ อย่าทำให้หน่วยความจำว่าง หรือตรวจสอบให้แน่ใจว่าไม่มีช่องว่างนำหน้า หรือเก็บบันทึกตัวชี้ที่ส่งคืนโดย malloc() รวมถึงชื่อที่พบโดย strtok() - person Jonathan Leffler; 18.02.2017