【问题标题】:char* producing unexpected results from procedure in nested structschar* 从嵌套结构中的过程产生意外结果
【发布时间】:2015-12-02 12:00:04
【问题描述】:

我正在开发一些从 xml 文档中检索某些值的程序,并使用嵌套结构指针来帮助我管理数据。

我的一个结构中的字符串值出现意外行为:

这是程序:

void parseInlineElements(xmlDocPtr doc, xmlNodePtr node, struct daastXML *xmlFile){

do {
    if (xmlStrcmp (node->name, XMLSTR("AdSystem")) == 0){

        xmlFile->Ads->data->Inline->AdSystem = (char *)node->children->content; // does not work - displays �9;
        xmlFile->Ads->data->Inline->AdSystem = "Works"; // works
        printf ((char *)node->children->content); // works
    }
    else if (xmlStrcmp (node->name, XMLSTR("Creatives")) == 0){
        parseCreatives (doc, node->children, xmlFile);
    }

    } while((node = node->next));

}

这是我遇到问题的行:

xmlFile->Ads->data->Inline->AdSystem = (char *)node->children->content;

当我在我的程序中测试结果时,该值似乎没有指向内存中的正确位置,因为它会产生垃圾,即:“�9”,其中预期值为“广告系统”

如果我存储一个测试值“Works” - 这里没有问题

如果我什至打印节点值,这也可以:“广告系统”

提前致谢

- 头文件

/*
* daastXML.h
 *
 *  Created on: Nov 27, 2015
 *      Author: hearme
 */

#ifndef DAASTXML_H_
#define DAASTXML_H_

#define VECTOR_INITIAL_CAPACITY 100

// Define a vector type
typedef struct {
    int size;               // slots used so far
    int capacity;           // total available slots
    struct daastAd *data;     // array of ads we're storing

    char * testData;
} VectorAds;

typedef struct {
    int size;               // slots used so far
    int capacity;           // total available slots
    struct daastCreative *data;     // array of ads we're storing
} VectorCreatives;

typedef struct {
    int size;
    int capacity;
    struct daastMediaFile *data;
} VectorMediaFiles;


struct daastInline {

    // Required elements
    char *AdTitle;
    char *Impression;
    VectorCreatives *Creatives;
    char *Category;

    // Optional elements
    char *AdSystem;
    char *Description;
    char *Advertiser;
    char *Expires;

    // Multiple survey urls
    // Multiple error urls

    char *Pricing;

    // Extensions - for custom xml extensions

};

struct daastXML {
    char *version;
    VectorAds *Ads;
};

struct daastAd {
    char *id;
    char *sequence;
    struct daastInline *Inline;
};

struct daastMediaFile {
    char *id;
    char *delivery;
    char *type;
    char *url;
    char *bitRate;
};

struct daastLinear {
    char *duration;
    VectorMediaFiles MediaFiles;

};

struct daastCreative {
    struct daastLinear linear;
};



// Main handler
void processDaast (char * filePath, struct daastXML *xmlFile);



// Methods used to manage Ads collection
void vectorAds_init(VectorAds *vector);
void vectorAds_append(VectorAds *vector, struct daastAd value);
struct daastAd vectorAds_get(VectorAds *vector, int index);
void vectorAds_set(VectorAds *vector, int index, struct daastAd value);
void vectorAds_double_capacity_if_full(VectorAds *vector);
void vectorAds_free(VectorAds *vector);

// Methods used to manage Creatives collection
void vectorCreatives_init(VectorCreatives *vector);
void vectorCreatives_append(VectorCreatives *vector, struct daastCreative value);
struct daastCreative VectorCreatives_get(VectorCreatives *vector, int index);
void vectorCreatives_set(VectorCreatives *vector, int index, struct daastCreative value);
void vectorCreatives_double_capacity_if_full(VectorCreatives *vector);
void vectorCreatives_free(VectorCreatives *vector);

// Methods used to manage Creatives collection
void vectorMediaFiles_init(VectorMediaFiles *vector);
void vectorMediaFiles_append(VectorMediaFiles *vector, struct daastMediaFile value);
struct daastMediaFile vectorMediaFiles_get(VectorMediaFiles *vector, int index);
void vectorMediaFiles_set(VectorMediaFiles *vector, int index, struct daastMediaFile value);
void vectorMediaFiles_double_capacity_if_full(VectorMediaFiles *vector);
void vectorMediaFiles_free(VectorMediaFiles *vector);


#endif /* DAASTXML_H_ */

C 文件 /* * daastXML.c * * 创建于:2015 年 11 月 27 日 * 作者:赫尔梅 */

#ifndef DAASTXML_C_
#define DAASTXML_C_

#define XMLSTR(str) ((xmlChar *)(str))

#include "daastXML.h"
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void parseAds(xmlDocPtr doc, xmlNodePtr node, struct daastXML *xmlFile);
void parseInline(xmlDocPtr doc, xmlNodePtr node, struct daastXML *xmlFile);
void parseInlineElements(xmlDocPtr doc, xmlNodePtr node, struct daastXML *xmlFile);
void parseCreatives(xmlDocPtr doc, xmlNodePtr node, struct daastXML *xmlFile);
void parseCreativesElements(xmlDocPtr doc, xmlNodePtr node, struct daastXML *xmlFile);
void parseCreativeElements(xmlDocPtr doc, xmlNodePtr node, struct daastXML *xmlFile);
void parseLinear (xmlDocPtr doc, xmlNodePtr node, struct daastXML *xmlFile);
void parseMediaFiles (xmlDocPtr doc, xmlNodePtr node, struct daastXML *xmlFile);


void processDaast (char * filePath, struct daastXML *xmlFile){

    xmlDocPtr doc;
    xmlNodePtr node;

    doc = xmlParseFile(filePath);
    node = xmlDocGetRootElement(doc);


    if (xmlStrcmp (node->name, XMLSTR("DAAST")) == 0){

        xmlFile->version = (char *)xmlGetProp(node, XMLSTR("version"));
        parseAds(doc, node->children, xmlFile);

    }

    xmlFreeDoc(doc);

}

void parseAds(xmlDocPtr doc, xmlNodePtr node, struct daastXML *xmlFile){

    // Allocate new instance of the VectorAds and assign it to the xmlFile, set default data
    VectorAds *Ads;
    Ads = (VectorAds *) malloc (sizeof(VectorAds));

    Ads->testData = "testData";
    xmlFile->Ads = Ads;

    // Initialise the vector
    vectorAds_init(xmlFile->Ads);



    do {
        if (node == NULL) break;
        if (xmlIsBlankNode(node)) continue;

    if (xmlStrcmp (node->name, XMLSTR("Ad")) == 0) {

        // Set up new advert
        struct daastAd *newAd;
        newAd = (struct daastAd *) malloc (sizeof(struct daastAd));

        // Set add properties
        newAd->id = (char *)xmlGetProp(node, XMLSTR("id"));
        newAd->sequence = (char *)xmlGetProp(node, XMLSTR("sequence"));

        vectorAds_append(xmlFile->Ads, *newAd);

        // At this point we need to get the inline (or wrapper) info *** WRAPPER NOT INTEGRATED ***
        parseInline (doc, node->children, xmlFile);

    }
} while ((node = node->next));


}

void parseInline (xmlDocPtr doc, xmlNodePtr node, struct daastXML *xmlFile){


// Set up Inline Property Here
struct daastInline *Inline;
Inline = (struct daastInline *) malloc (sizeof(struct daastInline));

// Assing Inline Property
xmlFile->Ads->data->Inline = Inline;

do {
    if (node->type == XML_ELEMENT_NODE){
        if (xmlStrcmp (node->name, XMLSTR("InLine")) == 0){

            // Various parses at this level
            parseInlineElements(doc, node->children, xmlFile);
            //xmlFile->Ads->data->Inline->AdSystem = "AdSystem";

            // Should this be here?
            //parseCreatives (doc, node->children, xmlFile);

            break;
        }
    }
} while((node = node->next));
}

void parseInlineElements(xmlDocPtr doc, xmlNodePtr node, struct daastXML *xmlFile){

// loop through Inline child elements, and pick out the values
//*
do {
    if (xmlStrcmp (node->name, XMLSTR("AdSystem")) == 0){
        char *nodeValue = (char *) node->children->content;
        xmlFile->Ads->data->Inline->AdSystem = malloc (sizeof(char));
        strcpy (xmlFile->Ads->data->Inline->AdSystem, nodeValue);
    }
    else if (xmlStrcmp (node->name, XMLSTR("AdTitle")) == 0){
        char *nodeValue = (char *) node->children->content;
        xmlFile->Ads->data->Inline->AdTitle = malloc (sizeof(char));
        strcpy (xmlFile->Ads->data->Inline->AdTitle, nodeValue);
    }
    else if (xmlStrcmp (node->name, XMLSTR("Category")) == 0){
        char *nodeValue = "";
        nodeValue = (char *) node->children->content;
        xmlFile->Ads->data->Inline->Category = malloc (sizeof(char));
        strcpy (xmlFile->Ads->data->Inline->Category, nodeValue);
    }
    else if (xmlStrcmp (node->name, XMLSTR("Advertiser")) == 0){
        char *nodeValue = (char *) node->children->content;
        xmlFile->Ads->data->Inline->Advertiser = malloc (sizeof(char));
        strcpy (xmlFile->Ads->data->Inline->Advertiser, nodeValue);
    }
    else if (xmlStrcmp (node->name, XMLSTR("Pricing")) == 0){
        char *nodeValue = (char *) node->children->content;
        xmlFile->Ads->data->Inline->Pricing = malloc (sizeof(char));
        strcpy (xmlFile->Ads->data->Inline->Pricing, nodeValue);
    }
    else if (xmlStrcmp (node->name, XMLSTR("Expires")) == 0){
        char *nodeValue = (char *) node->children->content;
        xmlFile->Ads->data->Inline->Expires = malloc (sizeof(char));
        strcpy (xmlFile->Ads->data->Inline->Expires, nodeValue);
    }
//      else if (xmlStrcmp (node->name, XMLSTR("Impression")) == 0){
//          char *nodeValue = (char *) node->children->next->content;
//          xmlFile->Ads->data->Inline->Impression = malloc (sizeof(char));
//          strcpy (xmlFile->Ads->data->Inline->Impression, nodeValue);
//
//      }
    else if (xmlStrcmp (node->name, XMLSTR("Creatives")) == 0){
        parseCreatives (doc, node->children, xmlFile);
    }

} while((node = node->next));

}


void parseCreatives(xmlDocPtr doc, xmlNodePtr node, struct daastXML *xmlFile){

// Need to set up a new Creatives and assign it to the nested struct pointer
VectorCreatives *Creatives;
Creatives = (VectorCreatives *) malloc (sizeof(VectorCreatives));

VectorAds *Ads;
Ads = (VectorAds *) malloc (sizeof(VectorAds));

xmlFile->Ads->data->Inline->Creatives = Creatives;

vectorCreatives_init(xmlFile->Ads->data->Inline->Creatives);

//*parseCreativesElements(doc, node->next, xmlFile);

}


void parseCreativesElements(xmlDocPtr doc, xmlNodePtr node, struct daastXML *xmlFile){

do {

    // Loop through the creatives - find the individual Creatives
    if (xmlStrcmp (node->name, XMLSTR("Creative")) == 0){

        // Various parses at this level
        parseCreativeElements(doc, node->children, xmlFile);
    }

} while ((node = node->next));
}

void parseCreativeElements(xmlDocPtr doc, xmlNodePtr node, struct daastXML *xmlFile){

do {
    if (xmlStrcmp (node->name, XMLSTR("Linear")) == 0){
        // Linear branch
        parseLinear(doc, node->children, xmlFile);

    } else if (xmlStrcmp (node->name, XMLSTR("CompanionAds")) == 0){
        // Companion Ad branch

    }
} while ((node = node->next));

}

void parseLinear(xmlDocPtr doc, xmlNodePtr node, struct daastXML *xmlFile){

do {

    if (xmlStrcmp (node->name, XMLSTR("Duration")) == 0){

        struct daastCreative newCreative;

        //*newCreative.linear.duration = node->children->content;

        //*vectorCreatives_append(&xmlFile->Ads.data->Inline.Creatives, newCreative);

    } else if (xmlStrcmp (node->name, XMLSTR("MediaFiles")) == 0){
        //parseMediaFiles(doc,node->children,xmlFile);
    }
} while ((node = node->next));

}


void parseMediaFiles(xmlDocPtr doc, xmlNodePtr node, struct daastXML *xmlFile){

//* vectorMediaFiles_init(&xmlFile->Ads.data->Inline.Creatives.data->linear.MediaFiles);

do {

    // Store all occurrences of Media Files
    if (xmlStrcmp (node->name, XMLSTR("MediaFile")) == 0){

        // Create a new Media File, and append
        struct daastMediaFile newMediaFile;

        newMediaFile.url = (char *) node->children->next->content;

        newMediaFile.id = (char *)xmlGetProp(node, XMLSTR("id"));
        newMediaFile.type = (char *)xmlGetProp(node, XMLSTR("type"));
        newMediaFile.bitRate = (char *)xmlGetProp(node, XMLSTR("bitrate"));
        newMediaFile.delivery = (char *)xmlGetProp(node, XMLSTR("delivery"));

        //*vectorMediaFiles_append(&xmlFile->Ads.data->Inline.Creatives.data->linear.MediaFiles, newMediaFile);

    }
} while ((node = node->next));

}


// ***************************************************************
// ***************************************************************
// ***************************************************************
// ***************************************************************


// Methods to manage collection (Ads)

void vectorAds_init(VectorAds *vector) {
  // initialize size and capacity
  vector->size = 0;
  vector->capacity = VECTOR_INITIAL_CAPACITY;

  // allocate memory for vector->data
  vector->data = malloc(sizeof(struct daastAd) * vector->capacity);
}

void vectorAds_append(VectorAds *vector, struct daastAd value) {
  // make sure there's room to expand into
  vectorAds_double_capacity_if_full(vector);

  // append the value and increment vector->size
  vector->data[vector->size++] = value;
}

struct daastAd vectorAds_get(VectorAds *vector, int index) {
  if (index >= vector->size || index < 0) {
    printf("Index %d out of bounds for vector of size %d\n", index, vector->size);
    exit(1);
  }
  return vector->data[index];
}

void vectorAds_set(VectorAds *vector, int index, struct daastAd value) {
  // zero fill the vector up to the desired index
  struct daastAd zero;
  while (index >= vector->size) {
    vectorAds_append(vector, zero);
  }

  // set the value at the desired index
  vector->data[index] = value;
}

void vectorAds_double_capacity_if_full(VectorAds *vector) {
  if (vector->size >= vector->capacity) {
    // double vector->capacity and resize the allocated memory accordingly
    vector->capacity *= 2;
    vector->data = realloc(vector->data, sizeof(struct daastAd) * vector->capacity);
  }
}

void vectorAds_free(VectorAds *vector) {
  free(vector->data);
}


// Methods to manage Creatives Vector

void vectorCreatives_init(VectorCreatives *vector) {
  // initialize size and capacity
  vector->size = 0;
  vector->capacity = VECTOR_INITIAL_CAPACITY;

  // allocate memory for vector->data
  vector->data = malloc(sizeof(struct daastCreative) * vector->capacity);
}

void vectorCreatives_append(VectorCreatives *vector, struct daastCreative value) {
  // make sure there's room to expand into
  vectorCreatives_double_capacity_if_full(vector);

  // append the value and increment vector->size
  vector->data[vector->size++] = value;
}

struct daastCreative vectorCreatives_get(VectorCreatives *vector, int index) {
  if (index >= vector->size || index < 0) {
    printf("Index %d out of bounds for vector of size %d\n", index, vector->size);
    exit(1);
  }
  return vector->data[index];
}

void vectorCreatives_set(VectorCreatives *vector, int index, struct daastCreative value) {
  // zero fill the vector up to the desired index
  struct daastCreative zero;
  while (index >= vector->size) {
    vectorCreatives_append(vector, zero);
  }

  // set the value at the desired index
  vector->data[index] = value;
}

void vectorCreatives_double_capacity_if_full(VectorCreatives *vector) {
  if (vector->size >= vector->capacity) {
    // double vector->capacity and resize the allocated memory accordingly
    vector->capacity *= 2;
    vector->data = realloc(vector->data, sizeof(struct daastCreative) * vector->capacity);
  }
}

void vectorCreatives_free(VectorCreatives *vector) {
  free(vector->data);
}


// Methods used to manage MediaFiles Vector

void vectorMediaFiles_init(VectorMediaFiles *vector) {
  // initialize size and capacity
  vector->size = 0;
  vector->capacity = VECTOR_INITIAL_CAPACITY;

  // allocate memory for vector->data
  vector->data = malloc(sizeof(struct daastMediaFile) * vector->capacity);
}

void vectorMediaFiles_append(VectorMediaFiles *vector, struct daastMediaFile value) {
  // make sure there's room to expand into
  vectorMediaFiles_double_capacity_if_full(vector);

  // append the value and increment vector->size
  vector->data[vector->size++] = value;
}

struct daastMediaFile vectorMediaFiles_get(VectorMediaFiles *vector, int index) {
  if (index >= vector->size || index < 0) {
    printf("Index %d out of bounds for vector of size %d\n", index, vector->size);
    exit(1);
  }
  return vector->data[index];
}

void vectorMediaFiles_set(VectorMediaFiles *vector, int index, struct daastMediaFile value) {
  // zero fill the vector up to the desired index
  struct daastMediaFile zero;
  while (index >= vector->size) {
    vectorMediaFiles_append(vector, zero);
  }

  // set the value at the desired index
  vector->data[index] = value;
}

void vectorMediaFiles_double_capacity_if_full(VectorMediaFiles *vector) {
  if (vector->size >= vector->capacity) {
    // double vector->capacity and resize the allocated memory accordingly
    vector->capacity *= 2;
    vector->data = realloc(vector->data, sizeof(struct daastMediaFile) * vector->capacity);
  }
}

void vectorMediaFiles_free(VectorMediaFiles *vector) {
  free(vector->data);
}

#endif /* DAASTXML_C_ */

XML 链接:http://hearme.fm/ars.xml

【问题讨论】:

  • node-&gt;children-&gt;content 所指向的内存会在您需要的整个过程中保持有效吗?在使用xmlFile-&gt;Ads-&gt;data-&gt;Inline-&gt;AdSystem 之前,您不会在任何地方使用free 吗?你如何检查内存的内容?你在哪里检查? node-&gt;children-&gt;content 已经被初始化为指向有效分配的内存?为什么要投射指针?你能告诉我们结构定义,或者至少是相关部分吗?如果您删除演员表,您会收到任何编译器警告或错误吗?如果启用更多警告会怎样(如果使用 GCC 或 Clang,请添加 -Wall -Wextra -pedantic)?
  • 你不应该直接printf一个字符串,如果字符串中有格式化字符可能会导致问题。
  • 我对 C 很陌生,但我怀疑你的意思是因为 ->AdSystem 有效地指向节点创建的值,当节点被释放时,也是价值?那是对的吗?我在我的主程序中检查值,我首先解析 xml 文档,释放 doc,然后返回 xmlFile。在这种情况下,分配此值的最佳方法是什么?我怀疑创建直接副本是正确的方法?
  • 如果我删除演员表没有警告
  • 你是在作业之前还是之后检查xmlFile-&gt;Ads-&gt;data-&gt;Inline-&gt;AdSystem?哦,请不要在 cmets 中添加代码,请编辑您的问题以包含它。

标签: c pointers struct char


【解决方案1】:

好的,

我已经修复了错误,但它看起来不是最干净的代码,也许有人可以建议这是否可以?

char *nodeValue = (char*) node->children->content;
xmlFile->Ads->data->Inline->AdSystem = (char *) malloc (sizeof(char));
strcpy (xmlFile->Ads->data->Inline->AdSystem, nodeValue);

【讨论】:

  • 不,不是。 1)你投了malloc()的结果,不要那样做。 2)您分配一个字节的内存,该字节已被字符串末尾的nul 使用。所以你必须只为这个空字符串遍历分配的内存。您必须分配适当的内存量。
  • 你需要分配足够的内存。应该是malloc(strlen(nodeValue)+1);。话虽如此,在做这样的事情之前,你需要学习字符串的基础知识。
  • 回到原来的问题,有没有人有简单有效的方式从节点值赋值?这似乎比它应该的更复杂
  • @GlennCooper,对我们来说这很复杂,因为您没有向我们展示一切。生成一个最小的完整示例,以便我们查看您的所有类型,甚至可以自己编译它。 stackoverflow.com/help/mcve
  • xmlFile->Ads->data->Inline->AdSystem 只是嵌套结构。 node->children->content 的类型为 xmlChar (xmlsoft.org/html/libxml-xmlstring.html#xmlChar)。我需要做的就是将节点中的字符串值分配给我的结构
【解决方案2】:

我已经修复了错误,但它看起来不是最干净的代码,也许 有人可以建议这是否可以?

char *nodeValue = (char*) node->children->content;
xmlFile->Ads->data->Inline->AdSystem = (char *) malloc (sizeof(char));
strcpy (xmlFile->Ads->data->Inline->AdSystem, nodeValue);

Sami Kuhmonen 和 Lundin 已经注意到分配的大小不是。

回到原来的问题,有没有人有一个简单有效的 从节点值分配值的方式?这个好像多了 比想象的要复杂

你是对的;如果您有 POSIX 系统,可以使用strdup() 简化上述操作:

xmlFile->Ads->data->Inline->AdSystem = strdup((char *)node->children->content);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-07
    • 2012-09-03
    • 1970-01-01
    • 1970-01-01
    • 2018-04-14
    • 2012-06-27
    • 2014-05-06
    相关资源
    最近更新 更多