初学者在这里。因此,我正在尝试编写一些包含句子并返回最长单词的代码。当我调试程序时,一切看起来都正确,包括char数组。但是,当我要打印输出时,我总是得到一个NULL ...
我输入了整个代码,因为我认为其中一个循环必须以某种方式影响数组字符串指针?
#include <stdio.h>
#include <string.h>
void LongestWord(char sen1[500]) {
/*
steps:
1. char pointer. Each Byte holds array position of each space or return value Note space = 32 & return = 10.
2. Once got above asses biggest word. Biggest word stored in short int (starting position)
3. Once got biggest word start - move to sen using strncpy
*/
char sen[500];
char *ptr = sen;
int i = 0;
int space_position[500];
int j = 0;
int k = 0;
int word_size_prior_to_each_position[500];
int l = 0;
int largest = 0;
int largest_end_position = 0;
int largest_start_position =0;
memset(&sen[0], 0, 500);
memset(&space_position[0], 0, 2000);
memset(&word_size_prior_to_each_position[0], 0, 2000);
while (i < 500) { //mark out where the spaces or final return is
if ((sen1[i] == 0b00100000) ||
(sen1[i] == 0b00001010))
{
space_position[j] = i;
j = j+1;
}
i = i+1;
}
while (k < 500) {
if (k == 0) {
word_size_prior_to_each_position[k] = (space_position[k]);
}
//calculate word size at each position
if ((k > 0) && (space_position[k] != 0x00)) {
word_size_prior_to_each_position[k] = (space_position[k] - space_position[k-1]) -1;
}
k = k+1;
}
while (l < 500) { //find largest start position
if (word_size_prior_to_each_position[l] > largest) {
largest = word_size_prior_to_each_position[l];
largest_end_position = space_position[l];
largest_start_position = space_position[l-1];
}
l = l+1;
}
strncpy(ptr, sen1+largest_start_position+1, largest);
printf("%s", *ptr);
return 0;
}
int main(void) {
char stringcapture[500];
fgets(stringcapture, 499, stdin);
LongestWord(stringcapture); //this grabs input and posts into the longestword function
return 0;
}
答案 0 :(得分:2)
在LongestWord函数中替换
printf("%s", *ptr);
使用
printf("%s\n", ptr);
*ptr
表示一个字符,但是您要打印一个字符串(请参见%s规范),因此必须改用ptr
。也可以添加一个换行符(\ n)。
也删除
return 0;
有,因为它是一个空函数。
返回最长的单词
要将函数中最长的单词作为指向char的指针返回,可以将函数签名更改为
char *LongestWord(char sen1[500])
由于指针ptr指向LongestWord中的本地数组,所以一旦函数返回,它将导致悬挂的引用。
因此,您需要执行以下操作:
return strdup(ptr);
然后在主要方面,您可以将代码更改为:
char *longest_word = LongestWord(stringcapture);
printf("%s\n", longest_word);
free(longest_word);
更多提示
您有一个声明
int space_position[500];
您正在呼叫:
memset(&space_position[0], 0, 2000);
在这里,您假设int为4个字节。这种假设导致了不可移植的代码。
您应该使用:
memset(&space_position[0], 0, sizeof(space_position));
您甚至可以写:
memset(space_position, 0, sizeof(space_position));
因为space_position始终是数组的地址。
应用于您的记忆集,它看起来像这样:
memset(sen, 0, sizeof(sen));
memset(space_position, 0, sizeof(space_position));
memset(word_size_prior_to_each_position, 0, sizeof(word_size_prior_to_each_position));
您可以选择使用可能更具可读性的符号''和'\ n'来代替空格和返回的二进制数,例如写:
if ((sen1[i] == ' ') ||
(sen1[i] == '\n'))
代替
if ((sen1[i] == 0b00100000) ||
(sen1[i] == 0b00001010))
已分配变量maximum_end_position,但从未在某处使用过。因此可以将其删除。
以下一行
strncpy(ptr, sen1 + largest_start_position + 1, largest);
如果第一个单词也最长,将省略该单词的第一个字母。似乎maximum_start_position是空间的位置,但是在第一个单词(largest_start_position == 0)的情况下,您将从索引1开始复制。这种特殊情况需要处理。
您的main中有一个未初始化的本地数组。 因此,而不是
char stringcapture[500];
你必须写
char stringcapture[500];
memset(stringcapture, 0, sizeof(stringcapture));
或者您可以使用:
char stringcapture[500] = {0};
最后一行:
largest_start_position = space_position[l - 1];
如果l == 0(space_position [-1]),则访问边界之外的数组。所以你必须写:
if (l > 0) {
largest_start_position = space_position[l - 1];
}
else {
largest_start_position = 0;
}
答案 1 :(得分:0)
尽管斯蒂芬(Stephan)为您提供了一个很好的答案,以解决您在实现LongestWord
函数时遇到的问题,但是您可能会为寻找最长的单词而过度复杂。
要有用,请考虑从句子中获取最长单词时需要了解的内容。您想知道(1)最长的单词是什么; (2)它包含几个字符?您总是可以在函数返回时再次调用strlen
,但是为什么呢?您已经在函数中处理了该信息,因此您最好也可以在调用方中使该信息可用。
您可以通过多种方式编写函数,以返回最长单词的长度或指向最长单词本身的指针,等等。如果要返回指向最长单词的指针,则可以传递足够大的数组作为函数的参数以填充到函数中,或者您可以在函数内动态分配存储,以便在函数返回时保留该存储(已分配存储持续时间与自动存储期限)。您还可以声明一个数组static
并以此方式保留存储,但这将限制您在任何一个表达式中使用该函数。如果要返回指向最长单词的指针,还可以在调用方中返回长度,则可以将指针作为参数传递,并在函数中更新该地址处的值,以使长度在调用函数中可用。>
只要您只是在寻找最长的单词,未删节词典中的最长单词(非医学)就是29个字符(总共存储30个字符),医学术语中最长的单词是45-字符(总共46个字符)。因此,简单地传递一个数组以填充最长的单词作为参数可能更有意义,因为您已经知道所需的最大长度是多少(64个字符的数组就足够了,或者将其加倍以免跳过缓冲区大小,您的调用。)
只需使用一个简单的循环和一对指针,而不是使用多个数组,便可以沿着句子缓冲区移动,并用括号括起来每个单词的开头和结尾以挑选最长的单词。 (与使用strtok
等相比,这样做的好处是,原始句子保持不变,允许以const char *
的形式传递,从而使编译器可以进一步优化代码)
一个longest_word
函数可以将句子和单词作为参数返回,以返回最长字符串的长度来填充,这很容易在一个循环中完成。简称为状态循环,您可以在其中使用一个简单的标志来跟踪读取状态,例如,您是句子中的in
单词还是之前的空格,在句子中的单词之间或之后。一个简单的输入/输出状态标志。
然后,您只需使用指针p
来定位每个单词的开头,并使用结束指针ep
来向下推动句子以定位每个单词的结尾,然后使用最大长度。您可以使用isspace()
中提供的ctype.h
宏来定位每个单词之间的空格。
循环本身无非是在跟踪每个指针的同时连续循环,然后在发现每个单词的末尾时通过简单的指针差ep - p
检查哪个单词最长。如果单词长于先前的max
,则将其复制到最长的单词数组中,并使用新的最大长度更新max
。
一个简短的实现可能类似于:
size_t longest_word (const char *sentence, char *word)
{
const char *p = sentence, *ep = p; /* pointer & end-pointer */
size_t in = 0, max = 0; /* in-word flag & max len */
if (!sentence || !*sentence) /* if NULL or empty, set word empty */
return (*word = 0);
for (;;) { /* loop continually */
if (isspace (*ep) || !*ep) { /* check whitespace & end of string */
if (in) { /* if in-word */
size_t len = ep - p; /* get length */
if (len > max) { /* if greater than max */
memcpy (word, p, len); /* copy to word */
word[len] = 0; /* nul-terminate word */
max = len; /* update max */
}
p = ep; /* update pointer to end-pointer */
in = 0; /* zero in-word flag */
}
if (!*ep) /* if end of word, bail */
break;
}
else { /* non-space character */
if (!in) { /* if not in-word */
p = ep; /* update pointer to end-pointer */
in = 1; /* set in-word flag */
}
}
ep++; /* advance end-pointer */
}
return max; /* return max length */
}
将句子作为用户输入的完整示例类似于:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAXWRD 64 /* longest word size */
#define MAXC 2048 /* max characters in sentence */
size_t longest_word (const char *sentence, char *word)
{
const char *p = sentence, *ep = p; /* pointer & end-pointer */
size_t in = 0, max = 0; /* in-word flag & max len */
if (!sentence || !*sentence) /* if NULL or empty, set word empty */
return (*word = 0);
for (;;) { /* loop continually */
if (isspace (*ep) || !*ep) { /* check whitespace & end of string */
if (in) { /* if in-word */
size_t len = ep - p; /* get length */
if (len > max) { /* if greater than max */
memcpy (word, p, len); /* copy to word */
word[len] = 0; /* nul-terminate word */
max = len; /* update max */
}
p = ep; /* update pointer to end-pointer */
in = 0; /* zero in-word flag */
}
if (!*ep) /* if end of word, bail */
break;
}
else { /* non-space character */
if (!in) { /* if not in-word */
p = ep; /* update pointer to end-pointer */
in = 1; /* set in-word flag */
}
}
ep++; /* advance end-pointer */
}
return max; /* return max length */
}
int main (void) {
char buf[MAXC], word[MAXWRD];
size_t len;
if (!fgets (buf, MAXC, stdin)) {
fputs ("error: user canceled input.\n", stderr);
return 1;
}
len = longest_word (buf, word);
printf ("longest: %s (%zu-chars)\n", word, len);
return 0;
}
使用/输出示例
输入的字符串具有2个字符的前导空格和2个字符的尾随空格:
$ ./bin/longest_word
1234 123 12 123456 1234 123456789 12345678 1 1234
longest: 123456789 (9-chars)
这并不是要代替Stephan的答案来帮助解决您实施中的紧迫问题,而是为您提供一个替代方法来思考问题的示例。通常,保留任何编码任务越简单,出错的可能性就越小。查看一下,让我知道您是否对该方法还有其他疑问。