C - 为什么 for 循环终止,但其中的 memcpy 复制相同的子字符串?



我的作业要求我们缩短用户输入句子的单词。然后将缩短的单词放入链表中。当代码的齿轮卡住时:句子中的最后一个单词被保存到每个节点中。应该实现什么修复,以便代码每次在节点中放置一个差异字。

注意:我查看了涉及memcpy的问题,并使用0和\0事先填充数组来实现。我还改变了memcpy的论点,有&和没有&。我还使用了memmove和strncpy。没有问过"memcpy in for loop将数组的子字符串复制到节点"的变体。

这是我的代码。感谢您在回答的评论中推荐学习资源链接到 c 或 java。以及改进代码的建议。当然,如果您对我的问题有更简洁/准确的版本,我很乐意更新它。谢谢!

#include <stdlib.h>
#include <stdio.h> 
#include <string.h>
#include <ctype.h>
typedef struct node
{
char *four_letters; 
struct node *next_node;
}node;
struct node* head= NULL; 
char sentence[120][40]={0}, four_letters[40]={0}; // Tried ,"0".
int word, num_words=-1; 
void scan(); void print(); void sentence_into_list();
void add(struct node **head, char *four_letters); 
void display(struct node *head);

int main()
{
scan();
printf("n");
print();
printf("n");
sentence_into_list();
display(head);
return 0;
}

void scan()
{
for(word=0;;word++)
{
scanf("%s",sentence[word]);
num_words++;
if(getchar()=='n')
break;
}
}
void print()
{
for(word=0;word<=num_words;word++)
{
printf("%s ", sentence[word]);
}
}
void sentence_into_list()
{   
for (word=0;word<=num_words;word++)
{
memcpy(four_letters, sentence[word], 4);     //tried & //tried strncpy, memmove.
add(&head, four_letters);
}
}
void add(struct node **head, char *four_letters)
{
struct node *new_node = malloc(sizeof(struct node));
new_node->four_letters = four_letters;
new_node->next_node = *head;
*head=new_node;
}
void display(struct node* head)
{
struct node *current;
current = head;
if(current!=NULL)
{
printf("List:");
do
{
printf("%s ",current->four_letters);
current = current->next_node;
}
while(current!=NULL);
printf("n");
}
else
{
printf("emptyn");
}
}

句子中的最后一个单词被保存到每个节点中。

发生这种情况是因为列表中所有节点four_letters指针指向相同的内存位置four_letters[char全局声明的缓冲区 -four_letters[40]={0};]。因此,无论four_letters的最后一个值是什么,都将反映在所有节点中。

解决此问题的一种方法是将足够
大的内存分配给节点four_letters指针,并将four_letters的内容复制到其中。或者,您可以使用strdup为您执行此操作。

因此,在add()函数中,将其替换为

new_node->four_letters = four_letters;

有了这个

new_node->four_letters = strdup(four_letters);

strdup创建传递给它的字符串的副本。它返回一个指向新分配的内存的指针,因此,您应该在完成它后free它,如下所示:

free (node_ptr->four_letters); //node_ptr is pointer to current node

在释放列表节点的动态分配内存时,请确保首先释放节点结构的动态分配成员,然后释放节点本身。

解决此问题的另一种方法是-
不要在结构node中使用指向char的指针,而是将char数组作为node结构的成员,如下所示:

typedef struct node
{
char four_letters[5]; // 5 because it is suppose to keep the four letters only and +1 is for null-terminating character
struct node *next_node;
}node;

并将传递给add()four_letters的内容复制到结构节点成员four_letters。有了这个,您无需注意释放内存。

你的代码还有一个问题-
在函数sentence_into_list()中,你正在做:

memcpy(four_letters, sentence[word], 4);
add(&head, four_letters);

在这里,您将sentence[word]的前4个字符复制到four_letters,但您还应该在缓冲区four_letters的第5个位置添加 null 终止字符,然后再将其传递给add(),如下所示:

four_letters[4] = '';

C 语言没有本机字符串类型。在 C 中,字符串实际上是以空字符结尾的一维字符数组。

您在代码中没有看到任何问题,因为您正在用零初始化缓冲区:

four_letters[40]={0};

每次您只将4字符复制到其中。因此,在第5位置,您始终拥有。但是假设您将缓冲区用于不同大小的字符串的情况。在这种情况下,您必须将终止空字符放在字符串的末尾。


附加

我可以看到您没有释放为列表节点动态分配的内存。遵循良好的编程实践,养成在完成动态分配的内存后释放动态分配的内存的习惯。

最新更新