创建一个函数,该函数接收两个列表(L1,L2),初始化L2,然后在L2中插入L1的元素(不包括奇数位置的元素)(假定列表的第一个元素的位置为零)。然后打印L2。
我的教授给了我们解决方案(如下),但是我需要创建一个main()来调用该函数并返回L2,并且由于我是新手,所以似乎没有任何作用。
我尝试初始化L1然后调用该函数,但是我得到的只是大量错误。
这是最终功能:
struct list{
int value;
struct list * nextPtr;
};
void createSubList(struct list * l1Ptr, struct list ** l2PtrPtr) {
init(l2PtrPtr);
while(l1Ptr!=NULL) {
pre_insert(l2PtrPtr, l1Ptr>value);
l1Ptr = l1Ptr>nextPtr;
if (l1Ptr != NULL)
l1Ptr = l1Ptr>nextPtr;
}
}
我希望在调用该函数后看到L2打印出来。 那是我的最终文件:
#include <stdlib.h>
#include <string.h>
struct list {
int value;
struct list *nextPtr;
};
void init( struct list **ptrptr){
*ptrptr!=NULL;
}
void prn (struct list * lptr) {
while (lptr) {
printf (" %d", lptr->value);
lptr = lptr->nextPtr;
}
putchar ('\n'); }
void pre_insert(struct list ** ptrptr, int value){
struct list * tmp_ptr;
tmp_ptr=*ptrptr;
*ptrptr=(struct list *)malloc(sizeof(struct list));
(*ptrptr)->value=value;
(*ptrptr)->nextPtr=tmp_ptr;
}
void createSubList(struct list* l1Ptr, struct list** l2PtrPtr) {
init(l2PtrPtr);
while(l1Ptr!=NULL) {
pre_insert(l2PtrPtr, l1Ptr->value);
l1Ptr = l1Ptr->nextPtr;
if (l1Ptr != NULL)
l1Ptr = l1Ptr->nextPtr;
}
prn(l1Ptr);
}
void main(){
struct list* l1Ptr;
init(&l1Ptr);
struct list* l2ptr;
init(&l2ptr);
pre_insert(&l1Ptr , 1);
pre_insert(&l1Ptr , 2);
pre_insert(&l1Ptr , 3);
pre_insert(&l1Ptr , 4);
pre_insert(&l1Ptr , 5);
pre_insert(&l1Ptr , 6);
createSubList(l1Ptr,&l2ptr);
}
我得到的错误:
[Finished in 0.1s with exit code -11]
[shell_cmd: gcc "/home/vittorio/Scrivania/CProjects/new.c" -o "/home/vittorio/Scrivania/CProjects/new" && "/home/vittorio/Scrivania/CProjects/new"]
[dir: /home/vittorio/Scrivania/CProjects]
[path: /home/vittorio/bin:/home/vittorio/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin]
答案 0 :(得分:0)
一旦获得非ASCII字符的平方就消失了。逐步实施您的实施。对于初学者,除非您使用的系统不合格,否则main
的正确声明是int main (void)
和int main (int argc, char **argv)
(将看到用等效的char *argv[]
编写)。 注释:main
是type int
的函数,它返回一个值。请参阅:C11 Standard §5.1.2.2.1 Program startup p1 (draft n1570)。另请参阅:What should main() return in C and C++?。
因此,对于符合标准的实现,不带参数的main()
应该是:
int main (void) {
struct list *l1Ptr = NULL;
struct list *l2ptr = NULL;
...
(注意:只需抛弃您的init()
函数,就不需要为设置指针NULL
设置函数调用开销
此过程中的下一个问题是您的pre_insert
必须区分将第一个节点添加到列表和添加所有其他节点。对于第一个节点,只需将*ptrptr
设置为初始化tmp_ptr
,即可建立列表的开头。对于其余节点,您使用的是 chaining ,其中您设置tmp_ptr->nextPtr = *ptrptr;
以使新节点中的下一个指针指向列表的旧开始,然后设置*ptrptr = tmp_ptr;
使其成为列表的新起点,例如
void pre_insert (struct list **ptrptr, int value)
{
struct list *tmp_ptr = malloc (sizeof *tmp_ptr); /* don't cast malloc */
if (tmp_ptr == NULL) { /* validate EVERY allocation */
perror ("malloc-tmp_ptr");
exit (EXIT_FAILURE);
}
tmp_ptr->value = value; /* initialize struct members */
tmp_ptr->nextPtr = NULL;
if (!*ptrptr) /* if 1st node, simply assign */
*ptrptr = tmp_ptr;
else {
tmp_ptr->nextPtr = *ptrptr; /* otherwise, set tmp->next to 1st */
*ptrptr = tmp_ptr; /* now set list to point to tmp */
}
}
您的createSubList
具有类似的冗余逻辑,表明您很挣扎。您只需要1/0 toggle 即可从list1添加或跳过节点。例如:
void createSubList (struct list *l1Ptr, struct list **l2PtrPtr)
{
int i = 0;
while (l1Ptr != NULL) {
if (i == 0) { /* only store even nodes */
pre_insert (l2PtrPtr, l1Ptr->value);
i = 1;
}
else
i = 0;
l1Ptr = l1Ptr->nextPtr;
}
}
如评论中所述,您需要一种打印列表的方法,同样重要的是,一种free
分配给完成处理的节点的内存的方法。简单的功能就是您所需要的,例如
void prnlist (struct list *lptr)
{
while (lptr) {
printf (" %d", lptr->value);
lptr = lptr->nextPtr;
}
putchar ('\n');
}
void freelist (struct list *lptr)
{
while (lptr) {
struct list *victim = lptr;
lptr = lptr->nextPtr;
free (victim);
}
}
(注意:您是否明白为什么必须保存指向当前节点的指针,然后在调用free
上的victim
之前使节点前进?)< / p>
就是这样,除了我在网上的其他评论。完全可以做到:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct list {
int value;
struct list *nextPtr;
};
void pre_insert (struct list **ptrptr, int value)
{
struct list *tmp_ptr = malloc (sizeof *tmp_ptr); /* don't cast malloc */
if (tmp_ptr == NULL) { /* validate EVERY allocation */
perror ("malloc-tmp_ptr");
exit (EXIT_FAILURE);
}
tmp_ptr->value = value; /* initialize struct members */
tmp_ptr->nextPtr = NULL;
if (!*ptrptr) /* if 1st node, simply assign */
*ptrptr = tmp_ptr;
else {
tmp_ptr->nextPtr = *ptrptr; /* otherwise, set tmp->next to 1st */
*ptrptr = tmp_ptr; /* now set list to point to tmp */
}
}
void createSubList (struct list *l1Ptr, struct list **l2PtrPtr)
{
int i = 0;
while (l1Ptr != NULL) {
if (i == 0) { /* only store even nodes */
pre_insert (l2PtrPtr, l1Ptr->value);
i = 1;
}
else
i = 0;
l1Ptr = l1Ptr->nextPtr;
}
}
void prnlist (struct list *lptr)
{
while (lptr) {
printf (" %d", lptr->value);
lptr = lptr->nextPtr;
}
putchar ('\n');
}
void freelist (struct list *lptr)
{
while (lptr) {
struct list *victim = lptr;
lptr = lptr->nextPtr;
free (victim);
}
}
int main (void) {
struct list *l1Ptr = NULL;
struct list *l2ptr = NULL;
for (int i = 1; i < 10; i++)
pre_insert (&l1Ptr , i);
createSubList (l1Ptr, &l2ptr);
prnlist (l2ptr); /* print list 2 */
freelist (l1Ptr); /* don't forget to free what you allocate */
freelist (l2ptr);
}
使用/输出示例
$ ./bin/llcreatesublist
1 3 5 7 9
内存使用/错误检查
在您编写的任何动态分配内存的代码中,对于任何分配的内存块,您都有2个职责:(1)始终保留指向起始地址的指针因此,(2)当不再需要它时可以释放。
当务之急是使用一个内存错误检查程序来确保您不会尝试访问内存或在已分配的块的边界之外/之外进行写入,不要试图以未初始化的值读取或基于条件跳转,最后,以确认您释放了已分配的所有内存。
对于Linux,valgrind
是正常选择。每个平台都有类似的内存检查器。它们都很容易使用,只需通过它运行程序即可。
$ valgrind ./bin/llcreatesublist
==23324== Memcheck, a memory error detector
==23324== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==23324== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==23324== Command: ./bin/llcreatesublist
==23324==
1 3 5 7 9
==23324==
==23324== HEAP SUMMARY:
==23324== in use at exit: 0 bytes in 0 blocks
==23324== total heap usage: 14 allocs, 14 frees, 224 bytes allocated
==23324==
==23324== All heap blocks were freed -- no leaks are possible
==23324==
==23324== For counts of detected and suppressed errors, rerun with: -v
==23324== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
始终确认已释放已分配的所有内存,并且没有内存错误。
仔细检查一下,如果还有其他问题,请告诉我。
答案 1 :(得分:0)
您需要添加#include <stdio.h>
在init
函数中,代码*ptrptr!=NULL;
应为*ptrptr=NULL;
,即没有!
然后将void main(){
更改为int main(){
那应该解决警告。
然后您需要进行实际的打印。因此,在main
中执行以下操作:
prn(l1Ptr);
createSubList(l1Ptr,&l2ptr);
prn(l2ptr);
BTW:请注意,prn(l1Ptr);
内的createSubList
将不会打印任何内容,因为调用l1Ptr
时prn
已经为NULL。因此,您只需要删除该行即可。
进行上述更改后,您的输出应为:
6 5 4 3 2 1
2 4 6
由于使用pre_insert
在前面添加了新节点,因此与原始列表相比,已创建的子列表已还原。