从函数接收一个字符串数组并找出它的长度

时间:2017-07-08 15:51:35

标签: c arrays string

我有这段代码:

char** SplitToWords(char* str);

int main()
{
    char** wordarr;
    char str[] = "This is a sentence";
    wordarr = SplitToWords(str);

    return 0;
}

主要功能实现后。

  1. 我不确定以下内容是否符合我的要求(即从函数中接收字符串数组):

    wordarr = SplitToWords(str);
    

    我以某种方式设法说服编译器确定它没问题,但我认为它只是做了别的事情。

  2. 如果是,我如何找出数组的长度(其中的字符串数)。

  3. 由于

3 个答案:

答案 0 :(得分:3)

我会尝试快速访问您可能尚未完全理解的所有方面:

  1. C中的字符串被描述为char s的连续序列,以值char的{​​{1}}结尾(作为字面值) :0)。它不是第一类对象,因此它没有自己的类型。因此,用于保存字符串的是'\0'的数组。因此,通过单词提问," 从函数中接收字符串数组"是不可能的。

  2. 数组是相同类型的连续对象序列。在C中,数组的标识符本身没有值;当它被评估时,它会作为指针衰减到数组的第一个元素。这在将数组传递给函数或从函数返回它们时尤其重要 - 您实际上无法传递数组,而是总是传递指针

    e.g。你可以写:

    char

    您已经将指针类型用于函数的参数和返回值,我认为理解完全发生的事情非常重要。

  3. 您编写char x[] = "foo"; // initialize a char array from a string literal char *xp = x; // here, x evaluates as a pointer to the first element of the array 并询问是否返回"字符串数组" - 好吧,那种,正如你在阅读1.和2.之后应该理解的那样 - 它的作用是返回指向char** SplitToWords(char* str);的指针。此指针可以是指向数组第一个元素的指针。所以在这种情况下,它会返回一个指向char *指针数组的指针。这些指针中的每一个本身都是指向char *数组的指针,因此指向字符串。但是非常重要的是要理解你永远不会返回一个数组,你总是返回一个指向它的指针。它非常重要,因为:

  4. 可能有想法做这样的事情:

    chars

    在这里,因为你没有返回数组 char** SplitToWords(char* str) { char *words[16]; // code to fill `words` with pointers to the actual words return words; // WRONG! } 而是指向它的指针(参见第2点),你返回一个指向 no的对象的指针存在时间words属于您的函数范围并具有自动存储持续时间,这意味着只有执行在函数内部时它才存在。一种解决方案是使用words存储类说明符声明words。这样,它可以在程序的整个执行时间内使用。但请注意,这也意味着只有一个实例,它始终是同一个对象。例如,这将是线程程序的主要问题。另一种方法是使用static 动态分配 words。但是,函数的调用者必须稍后malloc()

  5. 关于你的第二个问题,如何让调用者知道单词的数量 - 它已经在评论中了,但仅仅为了完整性,解决这个问题的典型方法是附加另一个< / em>条目是free()指针。因此调用者可以遍历指针,直到找到NULL

    关于你的评论,当然你可以在函数外部创建数组并传递指向函数的指针,因此函数只填充它。这是C中的一个常见习惯用法(例如,考虑NULL,该指针指向由函数填充字符串的fgets()数组。)

    以这种方式工作的函数需要一个额外的char参数,因此他们知道应该通过指针填充的数组的大小,否则你会有缓冲区溢出的风险(这就是为什么{ {3}}终于从C标准中删除。如果你决定调用者提供存储,你的函数应该有这个原型:

    size_t

    它应该被称为例如像这样:

    // returns the number of words found, up to `nwords`
    size_t SplitToTwords(char **words, size_t nwords, char *str);
    

    请记住,包含单词的字符串本身也需要存储空间。您可以操纵char *words[16]; size_t nwords = SplitToWords(words, 16, "the quick brown fox"); // returns 4 中的字节,在每个单词后插入str,覆盖第一个空格字符(这是'\0'所做的),或者您可以将单词复制到新字符串,但是你必须再次strtok(),然后调用者必须malloc()

答案 1 :(得分:1)

是的,您可以使用返回值为char **的函数来解决此问题。但是,之后无法找出有多少单词。

您可以通过为返回指针分配一个元素并将其设置为NULL来解决此问题。然后你可以用这段代码获得单词数:

wordarr = SplitToWords(str);
char **ptr=wordarr;
int noWords=0;
while(!*(ptr+noWords))
    noWords++;

但是如果要在C中返回多个数据,则需要定义返回struct或使用返回参数。在这种情况下,第一个选项看起来像这样:

typedef struct wordList {
    char **wordarr;
    int noWords;
}

wordList SplitToWords(char* str);

第二个:

char** SplitToWords(char* str, int *noWords);

void SplitToWords(char* str, char*** wordarr, int *noWords);

请注意,有三个*。那是因为我们希望它成为char **

的指针

答案 2 :(得分:0)

#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>  

#define MAXSTRINGS  5000


int main(int argc, char *argv[]) {

    char *stringTable[MAXSTRINGS];

    char sentence[] = "This is a sentence";

    char *token = NULL;

    int i = 0;

    while ((token = strtok(token == NULL ? sentence : NULL, " ")) != NULL)
    {
        printf("%s\n\r", token);
        stringTable[i] = (char *)malloc(strlen(token) + 1);  //have no "plain" C compiler - VS C++ used so cast needed :)
        strcpy(stringTable[i++], token);
    }
    stringTable[i] = NULL; // if you need to iterate through later
    printf("%d tokens found\n\r", i);

    for (int y = 0; y < i; y++)
        free(stringTable[y]);
}