【问题标题】:Creating the cartesian product of two lists into a new list in C在 C 中创建两个列表的笛卡尔积到一个新列表中
【发布时间】:2015-05-08 12:18:00
【问题描述】:

我想创建一个数组,它是两个数组的笛卡尔积。比如:

const char *first[] = {"1", "2","3"};
const char *second[] = { "a" , "b" , "c", "e"};

结果是数组:

Cartesian = {"(1,a)","(1,b)","(1,c)",....};

这是我现在拥有的:

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

    const char *first[] = {"1", "2","3"};
    const char *second[] = { "a" , "b" , "c", "e"};

    int size = sizeof(first) * sizeof(second);

    char *both[size];
    int i=0;

    for (int f=0; f<sizeof(first); f++) {  
       for (int s=0; s<sizeof(second); s++) {
          char *temp[size];
           strcpy(temp[s], "("+first[f]+ ","second[s]+")");
           both[i] = temp;
           i++;
       }
   }
   return 0;
}

【问题讨论】:

  • 你的问题是?
  • strcpy(temp[s], "("+first[f]+ ","second[s]+")");?您不能使用 + 运算符连接字符串。 temp[s] 没有分配内存。分配内存后使用sprintf(temp[s], "(%s,%s)",first[f],second[s]);
  • sizeof(first) --> sizeof(first) / sizeof(*first)
  • 在执行此操作之前,您必须研究数组的工作原理。 C 没有魔术字符串类,它需要在有效的读/写内存中分配数组。你的代码没有分配任何内存,所以程序充其量会崩溃。

标签: c arrays cartesian-product


【解决方案1】:

代码中的问题:

  1. sizeof(first)(和sizeof(second))给出number of string literals in the array * sizeof(char*)。您需要丢弃第二部分。只需将其除以sizeof(char*)sizeof(*str)@BLUEPIXY suggestedsizeof(str[0]) 相同:

    int size = (sizeof(first) / sizeof(*first)) * (sizeof(second) / sizeof(*second));
    
  2. 你的循环:

    for (int f=0; f<sizeof(first); f++)
    for (int s=0; s<sizeof(second); s++)
    

    遇到同样的问题。我建议使用

    int size1 = sizeof(first) / sizeof(*first);
    int size2 = sizeof(second) / sizeof(*second)
    
    for (int f=0; f < size1; f++)
    for (int s=0; s < size2; s++)
    
  3. 您的循环体有很多问题。从中删除所有内容。以下步骤显示了在那里做什么。

解决问题的步骤:

  1. 您需要为char *both[size]; 分配内存。从循环体分配内存:

    int i=0;
    
    for (int f=0; f < size1; f++)
    {
        for (int s=0; s < size2; s++)
        {
            both[i] = malloc(strlen(first[f]) + strlen(second[s]) + 4);
            /*Mallocing space for two brackets, a comma, a NUL-terminator and the coordinates*/
            i++; //Increment counter
        }
    }
    
  2. strcpy 是在这里使用的错误函数。请改用sprintf

    int i=0;
    
    for (int f=0; f < size1; f++)
    {
        for (int s=0; s < size2; s++)
        {
            both[i] = malloc(strlen(first[f]) + strlen(second[s]) + 4);
    
            sprintf(both[i], "(%s,%s)",first[f],second[s]); // Make the string
            i++;
        }
    }
    
  3. 循环之后,both 会根据您的需要填充。使用以下方式打印它们:

    for(int j=0; j<i ; j++)
        printf("%s \n",both[j]);
    
  4. 使用后,free分配的内存使用:

    for(int j=0; j<i ; j++)
        free(both[j]);
    

固定程序:

#include <stdio.h>
#include <stdlib.h> //For malloc and free
#include <string.h> //For strlen

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

    const char *first[] = {"1", "2","3"};
    const char *second[] = { "a" , "b" , "c", "e"};

    int size = (sizeof(first) / sizeof(*first)) * (sizeof(second) / sizeof(*second));

    char *both[size];
    int i=0;

    int size1 = sizeof(first) / sizeof(*first);
    int size2 = sizeof(second) / sizeof(*second)

    for (int f=0; f < size1; f++)
    {
        for (int s=0; s < size2; s++)
        {
            both[i] = malloc(strlen(first[f]) + strlen(second[s]) + 4);
            sprintf(both[i], "(%s,%s)",first[f],second[s]);
            i++;
        }
    }

    for(int j=0; j<i ; j++)
        printf("%s\n",both[j]);

    for(int j=0; j<i ; j++)
        free(both[j]);

    return 0; //or return(EXIT_SUCCESS);
}

其他说明:

  • 查看malloc的结果,看是否分配内存成功。 malloc 失败时返回 NULL
  • 检查sprintf 的结果也很好,虽然不是必须的。 sprintf 失败时返回负数。

【讨论】:

    【解决方案2】:

    程序可以如下所示

    #include <stdio.h>
    #include <string.h>
    
    int main( void )
    {
        const char *first[] = { "1", "2", "3" };
        const char *second[] = { "a" , "b" , "c", "e" };
        const size_t N = sizeof( first ) / sizeof( *first );
        const size_t M = sizeof( second ) / sizeof( *second );
        char product[N * M][3];
    
        for ( size_t i = 0; i < N; i++ )
        {
            for ( size_t j = 0; j < M; j++ )
            {
                strcpy( product[i*M + j], first[i] );
                strcat( product[i*M + j], second[j] );
            }
        }
    
        for ( size_t i = 0; i < N * M; i++ ) printf( "%s ", product[i] );
        printf( "\n" );
    
        return 0;
    }
    

    程序输出为

    1a 1b 1c 1e 2a 2b 2c 2e 3a 3b 3c 3e 
    

    如果你想将每个字符串括在括号中,那么程序可以看起来像

    #include <stdio.h>
    #include <string.h>
    
    int main( void )
    {
        const char *first[] = { "1", "2", "3" };
        const char *second[] = { "a" , "b" , "c", "e" };
        const size_t N = sizeof( first ) / sizeof( *first );
        const size_t M = sizeof( second ) / sizeof( *second );
        char product[N * M][6];
    
        for ( size_t i = 0; i < N; i++ )
        {
            for ( size_t j = 0; j < M; j++ )
            {
                strcpy( product[i*M + j], "(" );
                strcat( product[i*M + j], first[i] );
                strcat( product[i*M + j], "," );
                strcat( product[i*M + j], second[j] );
                strcat( product[i*M + j], ")" );
            }
        }
    
        for ( size_t i = 0; i < N * M; i++ ) printf( "%s ", product[i] );
        printf( "\n" );
    
        return 0;
    }
    

    程序输出是

    (1,a) (1,b) (1,c) (1,e) (2,a) (2,b) (2,c) (2,e) (3,a) (3,b) (3,c) (3,e) 
    

    还有循环

        for ( size_t i = 0; i < N; i++ )
        {
            for ( size_t j = 0; j < M; j++ )
            {
                strcpy( product[i*M + j], "(" );
                strcat( product[i*M + j], first[i] );
                strcat( product[i*M + j], "," );
                strcat( product[i*M + j], second[j] );
                strcat( product[i*M + j], ")" );
            }
        }
    

    可以使用sprintf(甚至snprintf)更简单地编写

    for ( size_t i = 0; i < N; i++ )
    {
        for ( size_t j = 0; j < M; j++ )
        {
            sprintf( product[i*M + j], "(%s,%s)", first[i], second[j] );
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2012-01-03
      • 2020-09-12
      • 1970-01-01
      • 2021-01-25
      • 2021-10-22
      • 2023-03-10
      • 2022-01-06
      • 1970-01-01
      • 2011-05-06
      相关资源
      最近更新 更多