将字符串转换为 C 中的字符串数组

Convert String into Array of Strings in C

我正在尝试拆分一串按字母顺序排序的单词 char *str = "a/apple/arm/basket/bread/car/camp/element/..." 像这样按字母顺序排列成一个字符串数组:

arr[0] = "a/apple/arm"
arr[1] = "basket/bread"
arr[2] = "car/camp"
arr[3] = ""
arr[4] = "element"
...

我对 C 不是很熟练,所以我的方法是声明:

char arr[26][100]; 
char curr_letter = "a";

然后遍历字符串中的每个字符以查找“/”,后跟 char != curr_letter,然后将该子字符串 strcpy 到正确的位置。

我不确定我的方法是否很好,更不用说如何正确实施了。 任何帮助将不胜感激!

所以我们基本上遍历字符串,检查我们是否找到“拆分字符”,我们还检查我们没有找到 'curr_letter' 作为下一个字符。

我们记录消耗的长度,即当前长度(用于memcpy之后将当前字符串复制到数组中)。

当我们找到可以将当前字符串添加到数组的位置时,我们分配space并将字符串复制到它作为数组中的下一个元素。我们还将 current_length 添加到 consumed,并重置 current_length。

我们使用due_to_end来判断当前字符串中是否有/,并相应地删除它。

尝试:

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

int main() {
        char *str = "a/apple/arm/basket/bread/car/camp/element/...";
        char split_char = '/';
        char nosplit_char = 'a';

        char **array = NULL;
        int num_elts = 0;

        // read all the characters one by one, and add to array if 
        // your condition is met, or if the string ends
        int current_length = 0; // holds the current length of the element to be added
        int consumed = 0; // holds how much we already added to the array
        for (int i = 0; i < strlen(str); i++) { // loop through string
                current_length++; // increment first
                int due_to_end = 0;
                if ( ( str[i] == split_char // check if split character found
                    && ( i != (strlen(str) - 1) // check if its not the end of the string, so when we check for the next character, we don't overflow
                    && str[i + 1] != nosplit_char ) ) // check if the next char is not the curr_letter(nosplit_char)
                   || (i == strlen(str) - 1 && (due_to_end = 1))) { // **OR**, check if end of string
                        array = realloc(array, (num_elts + 1) * sizeof(char *)); // allocate space in the array
                        array[num_elts] = calloc(current_length + 1, sizeof(char)); // allocate space for the string
                        memcpy(array[num_elts++], str + consumed, (due_to_end == 0 ? current_length - 1 : current_length)); // copy the string to the current array offset's allocated memory, and remove 1 character (slash) if this is not the end of the string

                        consumed += current_length; // add what we consumed right now
                        current_length = 0; // reset current_length
                }
        }

        for (int i = 0; i < num_elts; i++) { // loop through all the elements for overview
                printf("%s\n", array[i]);
                free(array[i]);
        }
        free(array);
}

是的,原则上,您在问题中指定的方法似乎不错。但是,我看到以下问题:

使用 strcpy 将需要 null-terminated 源字符串。这意味着如果你想使用 strcpy,你将不得不用空字符覆盖 /。如果您不想通过向其中写入空字符来修改源字符串,那么另一种方法是使用函数 memcpy 而不是 strcpy。这样,您可以指定要复制的确切字符数,并且不需要源字符串具有空终止字符。但是,这也意味着您将不得不以某种方式计算要复制的字符数。

另一方面,除了使用 strcpymemcpy,您可以简单地一次从 str 复制一个字符到 arr[0],直到遇到下一个字母,然后一次将一个字符从 str 复制到 arr[1],依此类推。该解决方案可能更简单。

根据the community guidelines for homework questions,我暂时不会为您的问题提供完整的解决方案。

编辑:由于另一个答案已经提供了一个使用 memcpy 的完整解决方案,我现在也将提供一个完整的解决方案,它使用上面提到的一次复制一个字符的更简单的解决方案:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define NUM_LETTERS 26
#define MAX_CHARS_PER_LETTER 99

int main( void )
{
    //declare the input string
    char *str =
        "a/apple/arm/basket/bread/car/camp/element/"
        "frog/glass/saddle/ship/water";

    //declare array which holds all the data
    //we must add 1 for the terminating null character
    char arr[NUM_LETTERS][MAX_CHARS_PER_LETTER+1];

    //this variable will store the current letter that we
    //have reached
    char curr_letter = 'a';

    //this variable will store the number of chars that are
    //already used in the current letter, which will be a
    //number between 0 and MAX_CHARS_PER_LETTER
    int chars_used = 0;

    //this variable stores whether the next character is
    //the start of a new word
    bool new_word = true;

    //initialize the arrays to contain empty strings
    for ( int i = 0; i < NUM_LETTERS; i++ )
        arr[i][0] = '[=10=]';

    //read one character at a time
    for ( const char *p = str; *p != '[=10=]'; p++ )
    {
        //determine whether we have reached the end of a word
        if ( *p == '/' )
        {
            new_word = true;
        }
        else
        {
            //determine whether we have reached a new letter
            if ( new_word && *p != curr_letter )
            {
                //write terminating null character to string of
                //previous letter, overwriting the "/"
                if ( chars_used != 0 )
                    arr[curr_letter-'a'][chars_used-1] = '[=10=]';

                curr_letter = *p;
                chars_used = 0;
            }

            new_word = false;
        }

        //verify that buffer is large enough
        if ( chars_used == MAX_CHARS_PER_LETTER )
        {
            fprintf( stderr, "buffer overflow!\n" );
            exit( EXIT_FAILURE );
        }

        //copy the character
        arr[curr_letter-'a'][chars_used++] = *p;
    }

    //the following code assumes that the string pointed to
    //by "str" will not end with a "/"

    //write terminating null character to string
    arr[curr_letter-'a'][chars_used] = '[=10=]';

    //print the result
    for ( int i = 0; i < NUM_LETTERS; i++ )
        printf( "%c: %s\n", 'a' + i, arr[i] );
}

这个程序有以下输出:

a: a/apple/arm
b: basket/bread
c: car/camp
d: 
e: element
f: frog
g: glass
h: 
i: 
j: 
k: 
l: 
m: 
n: 
o: 
p: 
q: 
r: 
s: saddle/ship
t: 
u: 
v: 
w: water
x: 
y: 
z: 

这是另一个使用 strtok:

的解决方案
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define NUM_LETTERS 26
#define MAX_CHARS_PER_LETTER 99

int main( void )
{
    //declare the input string
    char str[] =
        "a/apple/arm/basket/bread/car/camp/element/"
        "frog/glass/saddle/ship/water";

    //declare array which holds all the data
    //we must add 1 for the terminating null character
    char arr[NUM_LETTERS][MAX_CHARS_PER_LETTER+1];

    //this variable will store the current letter that we
    //have reached
    char curr_letter = 'a';

    //this variable will store the number of chars that are
    //already used in the current letter, which will be a
    //number between 0 and MAX_CHARS_PER_LETTER
    int chars_used = 0;

    //initialize the arrays to contain empty strings
    for ( int i = 0; i < NUM_LETTERS; i++ )
        arr[i][0] = '[=12=]';

    //find first token
    char *p = strtok( str, "/" );

    //read one token at a time
    while ( p != NULL )
    {
        int len;

        //determine whether we have reached a new letter
        if ( p[0] != curr_letter )
        {
            curr_letter = p[0];
            chars_used = 0;
        }

        //count length of string
        len = strlen( p );
            
        //verify that buffer is large enough to copy string
        if ( chars_used + len >= MAX_CHARS_PER_LETTER )
        {
            fprintf( stderr, "buffer overflow!\n" );
            exit( EXIT_FAILURE );
        }

        //add "/" if necessary
        if ( chars_used != 0 )
        {
            arr[curr_letter-'a'][chars_used++] =  '/';
            arr[curr_letter-'a'][chars_used]   = '[=12=]';
        }

        //copy the word
        strcpy( arr[curr_letter-'a']+chars_used, p );

        //update number of characters used in buffer
        chars_used += len;

        //find next token
        p = strtok( NULL, "/" );
    }

    //print the result
    for ( int i = 0; i < NUM_LETTERS; i++ )
        printf( "%c: %s\n", 'a' + i, arr[i] );
}