将字符串分配给 C 中具有隔离错误的结构



目前,我尝试解决考试中的练习以进行准备。在这里研究后,我改变了结构定义

char nr[10];
char name[25];

char *nr;
char *name;

将字符串(指向字符串的指针)传递到结构中(请参阅下面的整个代码)。

当我使用 Netbeans 8.2 和 Cygwin GCC 7.4.0 执行代码时,出现运行时错误。有时代码在没有终止的情况下无休止地运行,有时我得到一个分段错误。调试后,一旦编译器尝试执行,就会发生错误

new->item->nr = orderno;

我通过另一个带有气泡排序的练习意识到的,其中您有一个交换功能。我习惯像这样交换引用的值:

void swap(int *px, int *py) {
int temp = *px;
*px = *py;
*py = temp;
}

我想做的是使用这样的地址进行交换:

void swap(int *px, int *py) {
int *temp = px;
px = py;
py = temp;
}

Netbeans 通过无休止地运行而不终止交换函数或我正在为其创建主题的代码来显示相同的行为。有人知道我做错了什么吗?

#include <stdio.h>
#include <stdlib.h>
typedef struct litem_t {
char *nr;   // was char nr[10];
char *name; // was char name[25];
float price;
int cnt;
float sum;
} litem;
typedef struct llist_t {
struct litem_t *item;
struct llist_t *next;
} llist;
llist* addItem(llist *alist, char *orderno, char *name, float price, int count, float sum);
void dumpList(llist *alist);
void L_3_a_KL_17(int argc, char **argv) {
llist *alist;
alist = addItem(NULL, "AT 1001 C", "Pear jPhone Quad 64GB", 499.00, 1, 499.00);
alist = addItem(alist, "ZT 1012 D", "Pear jPhone Octa 128GB", 799.00, 1, 799.00);

dumpList(alist);
}
llist* addItem(llist *alist, char *orderno, char *name, float price, int count, float sum) {
llist *new = (llist *)malloc(sizeof(llist));
if(new == NULL)
return NULL;
new->item->nr = orderno; // runtime error here
new->item->name = name;
new->item->price = price;
new->item->cnt = count;
new->item->sum = sum;
new->next = alist;
return new;
}
void dumpList(llist *alist) {
llist *temp;
int j = 1;
while(alist != NULL) {
printf("n%d. Article:nNumber:t%snName:t%snPrice:t%.2fnCnt:t%dnSum:t%.2f",                                     
j, alist->item->nr, alist->item->name, alist->item->price, alist->item->cnt,
alist->item->summe);
temp = alist;
alist = alist->next;
free(temp);
j++;
}
}

基本上,代码应该读取文章,将它们按顺序存储在串联列表中,然后将它们打印在屏幕上。文章的顺序无关紧要。

感谢您的任何帮助。

韩国克朗

在你的列表源中有一些错误

ptr->item->nr = orderno;

将指向字符串的指针复制到结构中的指针。仅当字符串已存储在堆上并且您将指针作为函数调用中的参数传递时,这才有效。

在您的示例中,您仅复制字符串地址。如果在返回函数时该字符串不再可用,则指针不会指向预期的字符串。应将字符串复制到缓冲区,就像在第一个版本中定义的那样,或者确保只要数据结构内的指针具有其值,字符串就存在。

第二个问题是,您为列表条目分配内存,而不是为项目本身分配内存。这会导致您提到的错误。列表条目仅包含指向该项目的指针!因此,您还必须为该项目分配内存。如果此操作失败,则必须错误地处理已成功创建列表元素但未创建数据项的问题。

要回答您评论中的问题,请让我详细介绍一些细节

定义数据的结构类型

typedef struct litem_t {
char nr[10];   // was char nr[10];
char name[25]; // was char name[25];
float price;
int cnt;
float sum;
} litem;

以及一个带有用于链接项目的指针的结构:

typedef struct llist_t {
struct litem_t *item;
struct llist_t *next;
} llist;

请看这张图。您可以看到,您需要为每个新数据为这两个结构创建一个实例

Chained Instances               data instances 
of type llist                   of type litem

Size of each                    Size of each element 
instance is 8 byte              is 47 byte

[alist]
|
|                                 
'--> +--------+                   last created objects  
| item --|--------------->  +-----------+               
| next --|---.              | nr[10]    |   10 byte
+--------+   |              | name[25]  |   25 byte 
|              | price     |    4 byte     
.-----------------'              | cnt       |    4 byte   
|                                | sum       |    4 byte     
|                                +-----------+
'--> +--------+     
| item --|--------------->  +-----------+                        
| next --|---.              | nr[10]    |               
+--------+   |              | name[25]  |                 
|              | price     |                 
.-----------------'              | cnt       |                 
|                                | sum       |          
|                                +-----------+           
'--> +--------+                                         
| item --|---------------> +-----------+          
| next = NULL              | nr[10]    |                    
+--------+                 | name[25]  |                     
| price     |           
| cnt       |           
| sum       |           
+-----------+           
First created objects


图片显示您首先需要为 llist 项分配内存。比指针"项"存在,您可以为数据项分配内存。这两个项目必须单独释放,例如这样。

llist * next;
if (alist)
{
do
{
next = alist->next;  // temp. copy because pointer will be deleted
if (alist->item) free(alist->item);  // free memory for litem
free (alist);                        // free memory for llist
alist = next;                        // set alist to next item  
} while (alist != NULL)                  /7 very first entry has no "next"  
}

最好创建一个函数来释放单个项目并更正前一项的"下一个"指针。有了这个,您可以删除列表中的项目。恕我直言,这是使用链式列表的原因之一。

代码(无免费)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct litem_t {
char nr[10];   // was char nr[10];
char name[25]; // was char name[25];
float price;
int cnt;
float sum;
} litem;
typedef struct llist_t {
struct litem_t *item;
struct llist_t *next;
} llist;
llist* addItem(llist *alist, char const *orderno, char const *name, float price, int count, float sum);
void dumpList(llist *alist);
void L_3_a_KL_17(int argc, char **argv) {
llist *alist;
alist = addItem(NULL, "AT 1001 C", "Pear jPhone Quad 64GB", 499.00, 1, 499.00);
alist = addItem(alist, "ZT 1012 D", "Pear jPhone Octa 128GB", 799.00, 1, 799.00);

dumpList(alist);
}
llist* addItem(llist *alist, char const *orderno, char const *name, float price, int count, float sum) {
// Alloccate space for new list entry 
llist *newlistentry_ptr = (llist *)malloc(sizeof(llist));
if(newlistentry_ptr == NULL)
return NULL;

// Alloc space for new data item 
newlistentry_ptr->item = (litem *)malloc(sizeof(litem));   
if(newlistentry_ptr->item == NULL) {
// add here some error handling
// caller will not expect that item is NULL
// maybe free newlistentry_ptr for error detection
newlistentry_ptr->next = alist;
return newlistentry_ptr;
}
// Copy strings into a buffer where they are retained
strncpy (newlistentry_ptr->item->nr, orderno, sizeof(newlistentry_ptr->item->nr)); 
strncpy (newlistentry_ptr->item->name, name, sizeof(newlistentry_ptr->item->name));
newlistentry_ptr->item->price = price;
newlistentry_ptr->item->cnt = count;
newlistentry_ptr->item->sum = sum;
newlistentry_ptr->next = alist;
return newlistentry_ptr;
}
void dumpList(llist *alist) {
llist *temp;
int j = 1;
while(alist != NULL) {
printf("n%d. Article:nNumber:t%snName:t%snPrice:t%.2fnCnt:t%dnSum:t%.2f",                                     
j, alist->item->nr, alist->item->name, alist->item->price, alist->item->cnt,
alist->item->sum);
temp = alist;
alist = alist->next;
free(temp);
j++;
}
}

你可能想要这个:

void swap(int **px, int **py) {
int *temp = *px;
*px = *py;
*py = temp;
}
...
int *p1, *p2;
...
swap(&p1, &p2);

这不会做任何有用的事情:

void swap(int *px, int *py) {
int *temp = px;
px = py;
py = temp;
}

就像这不会做任何有用的事情一样:

void swap(int x, int x) {
int temp = x;
x = y;
y = temp;
}
#include <stdio.h>
void swap(int *px, int *py) {
int *temp = px;
px = py;
py = temp;
}
void bsort(int *v, int n) {
typedef char boolean;
boolean switch;
const boolean
FALSE = 0,
TRUE = 1;
do {
switch = FALSE;
for(int *i = v; i-v < n; i++)
if(*i > *(i+1)) {
swap(i, i+1)
switch = TRUE;
}
} while(switch);
}
void main(void) {
int
v[] = {42, 51, 13, 48, 92, 16, 9, 68},
n = (int)sizeof(v)/(int)sizeof(int);
bsort(v, n-1);
for(int *i = v; i-v < n; i++)
printf("%d "; *i);
}

交换函数应该切换地址,当我在调试模式下运行时,地址工作正常。离开函数时,指针被破坏并且引用丢失时是否存在相同的问题?我认为指针只是一个参考,无论如何都应该在交换函数中进行更改。你明白我的意思吗?

如果它与前一个问题相同,静态应该可以解决它,不是吗?

注意:您问第二个问题。似乎堆栈溢出不是这样工作的。如果还不清楚,您应该将新问题作为新主题提出。

你想换什么?我猜你想交换值。

在这种情况下,调用和函数签名是正确的,但交换实现不正确。你在 swap() 中交换指针,但这不会影响 i 或 i+1 或指针指向的数据。

您应该取消引用指针,然后交换数据

// px points to data cell 1 (as i)
// py pounts to data cell 2 (as i+1)
void swap (int * px, int * py)
{
int temp = *px;  // copy data cell 1 to temp
*px = *py;       // copy data cell 2 to data cell 1
*py = temp;      // copy temp to data cell 2
}

这实际交换数据 *i 和 *(i+1)

最新更新