I want to write a program in C that displays each word of a whole sentence (taken as input) at a seperate line. This is what i have done so far:
我想在C语言中编写一个程序,它将整个句子的每个单词(作为输入)显示在一个分离的行中。这是我迄今为止所做的:
void manipulate(char *buffer);
int get_words(char *buffer);
int main(){
char buff[100];
printf("sizeof %d\nstrlen %d\n", sizeof(buff), strlen(buff)); // Debugging reasons
bzero(buff, sizeof(buff));
printf("Give me the text:\n");
fgets(buff, sizeof(buff), stdin);
manipulate(buff);
return 0;
}
int get_words(char *buffer){ // Function that gets the word count, by counting the spaces.
int count;
int wordcount = 0;
char ch;
for (count = 0; count < strlen(buffer); count ++){
ch = buffer[count];
if((isblank(ch)) || (buffer[count] == '\0')){ // if the character is blank, or null byte add 1 to the wordcounter
wordcount += 1;
}
}
printf("%d\n\n", wordcount);
return wordcount;
}
void manipulate(char *buffer){
int words = get_words(buffer);
char *newbuff[words];
char *ptr;
int count = 0;
int count2 = 0;
char ch = '\n';
ptr = buffer;
bzero(newbuff, sizeof(newbuff));
for (count = 0; count < 100; count ++){
ch = buffer[count];
if (isblank(ch) || buffer[count] == '\0'){
buffer[count] = '\0';
if((newbuff[count2] = (char *)malloc(strlen(buffer))) == NULL) {
printf("MALLOC ERROR!\n");
exit(-1);
}
strcpy(newbuff[count2], ptr);
printf("\n%s\n",newbuff[count2]);
ptr = &buffer[count + 1];
count2 ++;
}
}
}
Although the output is what i want, i have really many black spaces after the final word displayed, and the malloc() returns NULL so the MALLOC ERROR! is displayed in the end. I can understand that there is a mistake at my malloc() implementation but i do not know what it is.
虽然输出是我想要的,但在显示最后一个词之后,我有很多黑色的空格,而malloc()返回NULL,所以malloc错误!显示在最后。我可以理解在malloc()实现中有一个错误,但是我不知道它是什么。
Is there another more elegant - generally better way to do it?
还有其他更优雅的方法吗?
Thanks in advance.
提前谢谢。
8 个解决方案
#1
65
http://www.cplusplus.com/reference/clibrary/cstring/strtok/
http://www.cplusplus.com/reference/clibrary/cstring/strtok/
Take a look at this, and use whitespace characters as the delimiter. If you need more hints let me know.
看一下这个,并使用空格字符作为分隔符。如果你需要更多的提示,请告诉我。
From the website:
从网站:
char * strtok ( char * str, const char * delimiters );
On a first call, the function expects a C string as argument for str, whose first character is used as the starting location to scan for tokens. In subsequent calls, the function expects a null pointer and uses the position right after the end of last token as the new starting location for scanning.
在第一个调用中,函数期望一个C字符串作为str的参数,它的第一个字符用作扫描标记的起始位置。在随后的调用中,函数期望一个空指针,并在最后一个标记结束后使用这个位置作为扫描的新起始位置。
Once the terminating null character of str is found in a call to strtok, all subsequent calls to this function (with a null pointer as the first argument) return a null pointer.
一旦在对strtok的调用中发现了str的终止null字符,随后所有对该函数的调用(以null指针作为第一个参数)返回一个空指针。
Parameters
- str
- C string to truncate.
- C字符串截断。
- Notice that this string is modified by being broken into smaller strings (tokens). Alternativelly [sic], a null pointer may be specified, in which case the function continues scanning where a previous successful call to the function ended.
- 注意,这个字符串被分解为更小的字符串(令牌)。可替换的[sic],可以指定一个空指针,在这种情况下,函数继续扫描之前成功调用该函数的地方。
- 字符串截断。注意,这个字符串被分解为更小的字符串(令牌)。可替换的[sic],可以指定一个空指针,在这种情况下,函数继续扫描之前成功调用该函数的地方。
- delimiters
- C string containing the delimiter characters.
- 包含分隔符字符的C字符串。
- These may vary from one call to another.
- 这些不同的呼叫可能会有所不同。
- 分隔符C字符串,包含分隔符。这些不同的呼叫可能会有所不同。
Return Value
A pointer to the last token found in string. A null pointer is returned if there are no tokens left to retrieve.
一个指向字符串中最后一个令牌的指针。如果没有要检索的令牌,则返回空指针。
Example
/* strtok example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="- This, a sample string.";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," ,.-");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ,.-");
}
return 0;
}
#2
4
For the fun of it here's an implementation based on the callback approach:
有趣的是,这里有一个基于回调方法的实现:
const char* find(const char* s,
const char* e,
int (*pred)(char))
{
while( s != e && !pred(*s) ) ++s;
return s;
}
void split_on_ws(const char* s,
const char* e,
void (*callback)(const char*, const char*))
{
const char* p = s;
while( s != e ) {
s = find(s, e, isspace);
callback(p, s);
p = s = find(s, e, isnotspace);
}
}
void handle_word(const char* s, const char* e)
{
// handle the word that starts at s and ends at e
}
int main()
{
split_on_ws(some_str, some_str + strlen(some_str), handle_word);
}
#3
1
malloc(0)
may (optionally) return NULL
, depending on the implementation. Do you realize why you may be calling malloc(0)
? Or more precisely, do you see where you are reading and writing beyond the size of your arrays?
malloc(0)可以(可选地)返回NULL,这取决于实现。你知道为什么你会打电话给malloc(0)吗?或者更准确地说,您是否看到了您正在读取和写入超出您的数组大小的地方?
#4
1
Consider using strtok_r
, as others have suggested, or something like:
考虑使用strtok_r,如其他人所建议的,或类似的:
void printWords(const char *string) {
// Make a local copy of the string that we can manipulate.
char * const copy = strdup(string);
char *space = copy;
// Find the next space in the string, and replace it with a newline.
while (space = strchr(space,' ')) *space = '\n';
// There are no more spaces in the string; print out our modified copy.
printf("%s\n", copy);
// Free our local copy
free(copy);
}
#5
0
Something going wrong is get_words()
always returning one less than the actual word count, so eventually you attempt to:
出错的地方是get_words()总是返回一个小于实际单词数的单词,所以最终您尝试:
char *newbuff[words]; /* Words is one less than the actual number,
so this is declared to be too small. */
newbuff[count2] = (char *)malloc(strlen(buffer))
count2
, eventually, is always one more than the number of elements you've declared for newbuff[]
. Why malloc()
isn't returning a valid ptr, though, I don't know.
最终,count2总是比您为newbuff声明的元素数量多一个。为什么malloc()没有返回有效的ptr,我不知道。
#6
0
You should be malloc'ing strlen(ptr), not strlen(buf). Also, your count2 should be limited to the number of words. When you get to the end of your string, you continue going over the zeros in your buffer and adding zero size strings to your array.
你应该是马洛奇·斯特伦(ptr),而不是strlen(buf)。另外,你的count2应该限制在单词的数量上。当您到达您的字符串的末尾时,您将继续越过缓冲区中的零,并向您的数组添加零大小的字符串。
#7
0
Just as an idea of a different style of string manipulation in C, here's an example which does not modify the source string, and does not use malloc
. To find spaces I use the libc function strpbrk
.
就像在C中使用不同风格的字符串操作一样,这里有一个不修改源字符串的例子,也不使用malloc。为了找到空格,我使用了libc函数strpbrk。
int print_words(const char *string, FILE *f)
{
static const char space_characters[] = " \t";
const char *next_space;
// Find the next space in the string
//
while ((next_space = strpbrk(string, space_characters)))
{
const char *p;
// If there are non-space characters between what we found
// and what we started from, print them.
//
if (next_space != string)
{
for (p=string; p<next_space; p++)
{
if(fputc(*p, f) == EOF)
{
return -1;
}
}
// Print a newline
//
if (fputc('\n', f) == EOF)
{
return -1;
}
}
// Advance next_space until we hit a non-space character
//
while (*next_space && strchr(space_characters, *next_space))
{
next_space++;
}
// Advance the string
//
string = next_space;
}
// Handle the case where there are no spaces left in the string
//
if (*string)
{
if (fprintf(f, "%s\n", string) < 0)
{
return -1;
}
}
return 0;
}
#8
-1
char arr[50];
gets(arr);
int c=0,i,l;
l=strlen(arr);
for(i=0;i<l;i++){
if(arr[i]==32){
printf("\n");
}
else
printf("%c",arr[i]);
}
#1
65
http://www.cplusplus.com/reference/clibrary/cstring/strtok/
http://www.cplusplus.com/reference/clibrary/cstring/strtok/
Take a look at this, and use whitespace characters as the delimiter. If you need more hints let me know.
看一下这个,并使用空格字符作为分隔符。如果你需要更多的提示,请告诉我。
From the website:
从网站:
char * strtok ( char * str, const char * delimiters );
On a first call, the function expects a C string as argument for str, whose first character is used as the starting location to scan for tokens. In subsequent calls, the function expects a null pointer and uses the position right after the end of last token as the new starting location for scanning.
在第一个调用中,函数期望一个C字符串作为str的参数,它的第一个字符用作扫描标记的起始位置。在随后的调用中,函数期望一个空指针,并在最后一个标记结束后使用这个位置作为扫描的新起始位置。
Once the terminating null character of str is found in a call to strtok, all subsequent calls to this function (with a null pointer as the first argument) return a null pointer.
一旦在对strtok的调用中发现了str的终止null字符,随后所有对该函数的调用(以null指针作为第一个参数)返回一个空指针。
Parameters
- str
- C string to truncate.
- C字符串截断。
- Notice that this string is modified by being broken into smaller strings (tokens). Alternativelly [sic], a null pointer may be specified, in which case the function continues scanning where a previous successful call to the function ended.
- 注意,这个字符串被分解为更小的字符串(令牌)。可替换的[sic],可以指定一个空指针,在这种情况下,函数继续扫描之前成功调用该函数的地方。
- 字符串截断。注意,这个字符串被分解为更小的字符串(令牌)。可替换的[sic],可以指定一个空指针,在这种情况下,函数继续扫描之前成功调用该函数的地方。
- delimiters
- C string containing the delimiter characters.
- 包含分隔符字符的C字符串。
- These may vary from one call to another.
- 这些不同的呼叫可能会有所不同。
- 分隔符C字符串,包含分隔符。这些不同的呼叫可能会有所不同。
Return Value
A pointer to the last token found in string. A null pointer is returned if there are no tokens left to retrieve.
一个指向字符串中最后一个令牌的指针。如果没有要检索的令牌,则返回空指针。
Example
/* strtok example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="- This, a sample string.";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," ,.-");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ,.-");
}
return 0;
}
#2
4
For the fun of it here's an implementation based on the callback approach:
有趣的是,这里有一个基于回调方法的实现:
const char* find(const char* s,
const char* e,
int (*pred)(char))
{
while( s != e && !pred(*s) ) ++s;
return s;
}
void split_on_ws(const char* s,
const char* e,
void (*callback)(const char*, const char*))
{
const char* p = s;
while( s != e ) {
s = find(s, e, isspace);
callback(p, s);
p = s = find(s, e, isnotspace);
}
}
void handle_word(const char* s, const char* e)
{
// handle the word that starts at s and ends at e
}
int main()
{
split_on_ws(some_str, some_str + strlen(some_str), handle_word);
}
#3
1
malloc(0)
may (optionally) return NULL
, depending on the implementation. Do you realize why you may be calling malloc(0)
? Or more precisely, do you see where you are reading and writing beyond the size of your arrays?
malloc(0)可以(可选地)返回NULL,这取决于实现。你知道为什么你会打电话给malloc(0)吗?或者更准确地说,您是否看到了您正在读取和写入超出您的数组大小的地方?
#4
1
Consider using strtok_r
, as others have suggested, or something like:
考虑使用strtok_r,如其他人所建议的,或类似的:
void printWords(const char *string) {
// Make a local copy of the string that we can manipulate.
char * const copy = strdup(string);
char *space = copy;
// Find the next space in the string, and replace it with a newline.
while (space = strchr(space,' ')) *space = '\n';
// There are no more spaces in the string; print out our modified copy.
printf("%s\n", copy);
// Free our local copy
free(copy);
}
#5
0
Something going wrong is get_words()
always returning one less than the actual word count, so eventually you attempt to:
出错的地方是get_words()总是返回一个小于实际单词数的单词,所以最终您尝试:
char *newbuff[words]; /* Words is one less than the actual number,
so this is declared to be too small. */
newbuff[count2] = (char *)malloc(strlen(buffer))
count2
, eventually, is always one more than the number of elements you've declared for newbuff[]
. Why malloc()
isn't returning a valid ptr, though, I don't know.
最终,count2总是比您为newbuff声明的元素数量多一个。为什么malloc()没有返回有效的ptr,我不知道。
#6
0
You should be malloc'ing strlen(ptr), not strlen(buf). Also, your count2 should be limited to the number of words. When you get to the end of your string, you continue going over the zeros in your buffer and adding zero size strings to your array.
你应该是马洛奇·斯特伦(ptr),而不是strlen(buf)。另外,你的count2应该限制在单词的数量上。当您到达您的字符串的末尾时,您将继续越过缓冲区中的零,并向您的数组添加零大小的字符串。
#7
0
Just as an idea of a different style of string manipulation in C, here's an example which does not modify the source string, and does not use malloc
. To find spaces I use the libc function strpbrk
.
就像在C中使用不同风格的字符串操作一样,这里有一个不修改源字符串的例子,也不使用malloc。为了找到空格,我使用了libc函数strpbrk。
int print_words(const char *string, FILE *f)
{
static const char space_characters[] = " \t";
const char *next_space;
// Find the next space in the string
//
while ((next_space = strpbrk(string, space_characters)))
{
const char *p;
// If there are non-space characters between what we found
// and what we started from, print them.
//
if (next_space != string)
{
for (p=string; p<next_space; p++)
{
if(fputc(*p, f) == EOF)
{
return -1;
}
}
// Print a newline
//
if (fputc('\n', f) == EOF)
{
return -1;
}
}
// Advance next_space until we hit a non-space character
//
while (*next_space && strchr(space_characters, *next_space))
{
next_space++;
}
// Advance the string
//
string = next_space;
}
// Handle the case where there are no spaces left in the string
//
if (*string)
{
if (fprintf(f, "%s\n", string) < 0)
{
return -1;
}
}
return 0;
}
#8
-1
char arr[50];
gets(arr);
int c=0,i,l;
l=strlen(arr);
for(i=0;i<l;i++){
if(arr[i]==32){
printf("\n");
}
else
printf("%c",arr[i]);
}