我在下面的代码中尝试做的是标记字符串并将每个标记存储在动态分配的结构中,但不包括任何重复项。
这段代码有用,直到我输入一个包含两个相等单词的字符串。例如,字符串“this this”也将存储第二个单词,即使它是相同的。但是如果我输入“this this is”,它将删除第二个“this”,并完全忽略字符串的最后一个单词,这样如果字符串中有重复,它就不会被删除。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define dim 70
typedef struct string {
char* token[25];
} string;
int main() {
string* New = malloc(dim*sizeof(string));
char* s;
char* buffer = NULL;
int i = 0, r = 0;
s = malloc(dim * sizeof(char));
fgets(s, dim, stdin);
printf("The string is: %s\n", s);
New->token[i] = malloc(dim*sizeof(char));
New->token[i] = strtok(s, " ");
++i;
while((buffer = strtok(NULL, " ")) && buffer != NULL){
printf("\nbuffer is: %s", buffer);
for(r = 0; r < i; ++r) {
if(strcmp(New->token[r], buffer) != 0 && r == i-1) {
New->token[i] = malloc(strlen(buffer)*sizeof(char)+1);
New->token[i] = buffer;
++i;
}
else if(New->token[r] == buffer) {
break;
}
}
}
printf("\n New string: ");
for(i = 0; New->token[i] != NULL; ++i) {
printf(" %s", New->token[i]);
}
return 0;
}
在我看来这应该工作正常,但我真的很难找到我在这里做错了什么。如果您需要其他信息请问我,我为任何最终缺乏明确性(以及我的英语)道歉。
完全重写这个答案,以解决我第一次看不到的一些根本错误的事情。请参阅底部代码中的内联注释,以解释一些构造更改:
我完全按原样运行你的代码并看到你正在描述的内容,除了在另一个答案中使用strcmp
的注释之外,还发现了几行代码可以调整或删除,以使其按照你的描述进行操作:
首先,struct定义创建一个指向char数组的指针。根据您在代码中稍后所做的事情,您需要的是一个简单的char数组
typedef struct string {
//char* token[25]; //this create a pointer to array of 25 char
char token[25]; //this is all you need
} string;
正如您稍后将看到的,这将大大简化内存分配。
一些基本问题:
在解析分隔符中包含\n
换行符。当<enter>
被命中为输入字符串的结尾时,会附加一个换行符,导致this
的第一个实例和this\n
的第二个实例不相等。
while((buffer = strtok(NULL, " \n")) && buffer != NULL){
^^
这一行正在创建未初始化的内存。
string* New = malloc(dim*sizeof(string));
关于使用malloc()与calloc()的注意事项:malloc()会保留未创建的内存,而calloc()会创建一个全部初始化为0
的内存块。
使用malloc()
创建的内存
使用calloc()
创建的内存:
这在代码中的几个地方变得很重要,但特别是我在上一节中看到了一个问题:
for(i = 0; New->token[i] != NULL; ++i) {
printf(" %s", New->token[i]);
}
如果为New
创建的内存未初始化,则当索引i
增加超出您已明确写入的内存区域时,可能会出现运行时错误,并循环尝试测试New->token[i]
。如果New->token[i]
包含除0
之外的任何内容,它将尝试打印该内存区域。
您还应该释放代码中创建的每个内存实例,并调用free()。
所有这些以及更多内容都在下面的代码重写中得到解决:(针对此测试的是字符串字符串。)
typedef struct string {
//char* token[25]; //this create a pointer to array of 25 char
char token[25]; //this is all you need
} string;
int main() {
char* s;
char* buffer = NULL;
int i = 0, r = 0;
string* New = calloc(dim, sizeof(string));//Note: This creates an array of New.
//Example: New[i]
//Not: New->token[i]
s = calloc(dim , sizeof(char));
fgets(s, dim, stdin);
printf("The string is: %s\n", s);
buffer = strtok(s, " \n");
strcpy(New[i].token, buffer); //use strcpy instead of = for strings
//restuctured the parsing loop to a more conventional construct
// when using strtok:
if(buffer)
{
++i;
while(buffer){
printf("\nbuffer is: %s", buffer);
for(r = 0; r < i; ++r) {
if(strcmp(New[r].token, buffer) != 0 && r == i-1) {
strcpy(New[i].token, buffer);
++i;
}
else if(strcmp(New[r].token, buffer)==0) {
break;
}
}
buffer = strtok(NULL, " \n");
}
}
printf("\n New string: ");
for(i = 0; i<dim; i++) {
if(New[i].token) printf(" %s", New[i].token);
}
free(New);
free(s);
return 0;
}
您比较指针而不是比较字符串。更换
}
else if(New->token[r] == buffer) {
break;
同
}
else if(strcmp(New->token[r], buffer) == 0) {
break;
您还需要复制缓冲区:
memcpy(New->token[i],buffer,strlen(buffer)+1);
代替
New->token[i] = buffer;
或用。替换两行(以及malloc)
New->token[i] = strdup(buffer);
最好用strtok
替换strtok_r
(strtok不是重入)。
结构似乎没必要。
这使用指针数组来存储令牌。
可以使用strspn
和strcspn
解析输入。
唯一标记将添加到指针数组中。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DIM 70
int main() {
char* token[DIM] = { NULL};
char s[DIM];
char* buffer = s;
int unique = 0, check = 0;
int match = 0;
int loop = 0;
size_t space = 0;
size_t span = 0;
fgets(s, DIM, stdin);
printf("The string is: %s\n", s);
while ( unique < DIM && *buffer){//*buffer not pointing to zero terminator
space = strspn ( buffer, " \n\t");//leading whitespace
buffer += space;//advance past whitespace
span = strcspn ( buffer, " \n\t");//not whitespace
if ( span) {
printf("\ntoken is: %.*s", (int)span, buffer );//prints span number of characters
}
match = 0;
for ( check = 0; check < unique; ++check) {
if ( 0 == strncmp ( token[check], buffer, span)) {
match = 1;//found match
break;
}
}
if ( ! match) {//no match
token[unique] = malloc ( span + 1);//allocate for token
strncpy ( token[unique], buffer, span);//copy span number of characters
token[unique][span] = 0;//zero terminate
++unique;//add a unique token
}
buffer += span;//advance past non whitespace for next token
}
printf("\n New string: ");
for( loop = 0; loop < unique; ++loop) {
printf(" %s", token[loop]);//print the unique tokens
}
printf("\n");
for( loop = 0; loop < unique; ++loop) {
free ( token[loop]);//free memory
}
return 0;
}