2009-03-30 8 views
4

Existe-t-il un moyen facile de référencer une colonne dans un tableau 2-D en tant que tableau 1D distinct dans tout simplement ancien C (pas C++ ou C#)? C'est facile de faire ça pour la suite. Asssume J'ai 2 fonctions:Référence d'une colonne de tableau à deux dimensions dans C?

double doSomethingWithARow(double theRow[3]); 
double doSomethingWithACol(double theCol[100]); 

Ensuite, je pourrais utiliser le premier comme ceci:

double matrix[100][3]; 
double result; 

// pass a single row to a function as an array 
// this essentially passes the 3-element array at row 48 to the function 
for(int i=0; i < 100; i++) 
{ 
    result = doSomethingWithARow(matrix[i]); 
} 

Ce que je veux un moyen d'accéder à une colonne facilement. La seule chose que j'ai trouvé jusqu'à présent est de transformer la matrice pour échanger les rangées avec les colonnes. Mais ce code est censé être aussi efficace que possible en termes de mémoire et de rapidité. Avec toutes les manières compliquées de référencer les pointeurs en C, il semble qu'il devrait y avoir un moyen de le faire.

Répondre

3

Une façon de typesafe agréable de le faire sans spécifier les dimensions en tant que paramètres séparés est la suivante:

#define ROWS 100 
#define COLUMNS 30 

void doSomethingToAllRows(double (*row)[ROWS][COLUMNS], int col, double val) 
{ 
    for(size_t i = 0; i < ROWS; ++i) 
     (*row)[i][col] = val; 
} 

void doSomethingToAllColumns(double (*col)[ROWS][COLUMNS], int row, double val) 
{ 
    for(size_t i = 0; i < COLUMNS; ++i) 
     (*col)[row][i] = val; 
} 

int main(int argc, char **argv) 
{ 
    double matrix[ROWS][COLUMNS]; 

    /* Modify each column of the 10th row with the value of 3 */ 
    doSomethingToAllColumns(&matrix, 10, 3); 

    /* Modify each row of the 10th column with the value of 3 */ 
    doSomethingToAllRows(&matrix, 10, 3); 

    return 0; 
} 

Il est tout à fait tort de passer un double ** pour cette raison:

void test() 
{ 
    double **a; 
    int i1 = sizeof(a[0]);//i1 == 4 == sizeof(double*) 

    double matrix[ROWS][COLUMNS]; 
    int i2 = sizeof(matrix[0]);//i2 == 240 == COLUMNS * sizeof(double) 
} 

Si vous avez passé dans un double ** puis accédaient comme un tableau vous causer un accident, ou segfault un comportement non défini.

+0

Vos fonctions utilisent des références alors que l'affiche originale spécifiée C A part cela, c'est une bonne solution si vous êtes désespéré d'éviter d'utiliser un conteneur. –

+0

@Andrew Grant: Bon point, je l'ai changé en pointeurs. –

+0

+1, car ce code doit être préféré à ma solution si les dimensions des tableaux utilisés dans le programme sont fixes. – Stephan202

0

Étant donné que les "colonnes" telles que vous les appelez sont stockées de manière discontigeante en mémoire, il n'y a pas de véritable moyen de les supprimer directement.

Vous pouvez cependant créer un tableau de pointeurs et stocker des références aux index de l'autre tableau dans celui-ci. Vous auriez besoin de parcourir tous les éléments de votre tableau, donc ce n'est probablement pas une meilleure solution que n'importe quelle autre. En fonction de la fréquence à laquelle vous devez accéder au tableau par colonne, cela peut en valoir la peine.

5

Eh bien, vous auriez à passer la taille d'une ligne, et le nombre de lignes:

double doSomethingWithACol(double *matrix, size_t colID, size_t rowSize, size_t nRows); 

Maintenant, vous pouvez utiliser le fait que la matrice [i] [j] = matrice + i * rowSize + j;

Sinon, vous pouvez également utiliser la signature suivante:

double doSomethingWithACol(double *colPtr, size_t rowSize, size_t nRows); 

Ici, vous devrez passer le pointeur sur le premier élément de la colonne que vous voulez traiter, au lieu du pointeur à la première rangée.


code Exemple: Ce code résume les éléments de la seconde colonne (compiler avec gcc -o principal -Wall -Wextra -pedantic std = c99 test.c):

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

double colSum1(double *matrix, size_t colID, size_t rowSize, size_t nRows) 
{ 
    double *c = NULL, *end = matrix + colID + (nRows * rowSize); 
    double sum = 0; 

    for (c = matrix + colID; c < end; c += rowSize) { 
    sum += *c; 
    } 

    return sum; 
} 

double colSum2(double *colPtr, size_t rowSize, size_t nRows) 
{ 
    double *end = colPtr + (nRows * rowSize); 
    double sum = 0; 

    for (; colPtr < end; colPtr += rowSize) { 
    sum += *colPtr; 
    } 

    return sum; 
} 

int 
main(void) 
{ 
    double matrix[4][3] = { 
    {0, 1, 2}, 
    {3, 4, 5}, 
    {6, 7, 8}, 
    {9, 10, 11} 
    }; 

    printf("%f\n", colSum1(*matrix, 1, 3, 4)); 
    printf("%f\n", colSum2(&matrix[0][1], 3, 4)); 
    printf("%f\n", colSum2(matrix[0] + 1, 3, 4)); 

    return EXIT_SUCCESS; 
} 
+0

Vous me battez à ce .... –

+0

Cela ne fera pas ce que vous pensez. C'est complètement faux de passer en double **. Cela provoquera une erreur de segmentation dans l'application. J'explique plus dans ma réponse. –

+0

Le double ** n'est pas nécessaire; J'ai remarqué cela quand j'ai écrit mon code d'exemple. Cependant, cela n'a rien à voir avec les erreurs de segmentation. – Stephan202

0

Vous ne pouvez pas vraiment faire cela, car les tableaux dans C sont stockés de telle sorte que les éléments de chaque rangée sont stockés ensemble. Cela signifie qu'une rangée d'un tableau est un bloc continu de mémoire, et en ce qui concerne C, cela pourrait aussi bien être un tableau indépendant lui-même. Cela ne fonctionne pas de la même manière avec les colonnes car les éléments d'une colonne ne sont pas continus en mémoire; ils sont plutôt espacés de N octets, chaque ligne ayant une longueur de N octets. Cela signifie que vous pouvez accéder efficacement aux divers éléments d'une colonne d'un tableau 2D en utilisant l'arithmétique du pointeur, mais il est impossible de transformer une colonne en tableau lui-même autrement qu'en copiant les éléments dans un nouveau tableau.

0

Non, il n'y en a pas. Il ne peut y avoir, puisque dans C, un tableau est une partie consécutive de la mémoire, et il est trivial que les lignes et colonnes ne peuvent pas être consécutives en même temps.Ceci étant dit, il est assez facile de passer d'une cellule d'une colonne à l'autre, si vous connaissez la longueur des lignes. Prenons l'exemple suivant:

void processColumn(double *array, int colIdx, int rowLen, int rowCnt) { 
    for (int i = colIdx; i < rowCnt * rowLen; i += rowLen) { 
     // do whatever you want 
    } 
} 

#define N 5 
#define M 10 

double array[N*M]; 

processColumn(array, 3, N, M); 
Questions connexes