1

I'd like to make a 1D array 2D.

Right now I can only transfer 1 item in this array, like so:

patches[0] = "This is item 1";
patches[1] = "This is item 2";

What I want to be able to do:

patches[0][0] = "Version 1.01";
patches[0][1] = "Size 1GB";
patches[0][2] = "Is compatible";

patches[1][0] = "Version 4.01";
patches[1][1] = "Size 4GB";
patches[1][2] = "Is compatible";

This is what I currently have:

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

int test() {
     char** patches = NULL;
     
     int size = 10;
     
    patches = (char**)malloc(size * sizeof(*patches));
    if (!patches) {
        printf("No memory.\n");
        return 1;
    }
    memset(patches, 0, size * sizeof(*patches));
    
    for (int i = 0; i < size; ++i) {
         patches[i] = "Test";
    }
    
    printf("%s\n", patches[0]);
    
    return 0;
}

int main()
{
    test();

    return 0;
}

How can I achieve this?

Appel Flap
  • 261
  • 3
  • 23
  • Did you mean to increment `i` twice in the `for` loop? – Weather Vane Jul 28 '20 at 18:39
  • @WeatherVane No sir, I have corrected it – Appel Flap Jul 28 '20 at 18:40
  • 1
    I suggest once you need to extend the code to *three-star* pointers it is time to rethink the approach. If the code has string literal definitions, they are known at compile time. – Weather Vane Jul 28 '20 at 18:41
  • You might consider an array of `struct` where each `struct` has a pointer for the version string, the memory size string, and the compatibility string. – user3386109 Jul 28 '20 at 18:55
  • Architecturally I agree with Weather Vane (discouraging the `***` approach), but if you are really wanting to use this approach, it requires either freeing _all_ the pointers used to construct the first set of memory locations, and reallocating memory to support your desired shape. A better approach might be to use linked lists. Then you can easily add or remove instances of data sets. – ryyker Jul 28 '20 at 18:55

2 Answers2

1

"...How can I achieve this?"

Probably not using arrays.

Arrays in C are rigidly defined contiguous sets of memory locations, created on the stack. This type of array is generally recommended over dynamically allocated variations when size, shape of the array are known at compile-time. Once created, the size and shape of the array created with this method is not changeable. Arrays can be created for a single type variables, as well as for struct type data, allowing variations of type to exist within each array element.

When run-time flexibility is needed there are other methods to consider, such as the following:

  • Dynamically allocated arrays. Although commonly referred to as arrays, are actually blocks of addressable (and depending on how implemented, may be contiguous) memory created on the heap. These are created in any number of dimensions, and like arrays, elements are accessible via indexing, eg array[i][j][k]. This type of dynamic array is recommended over a normal C array only when the size or shape of the array is not known until run-time. Once created its dimensions can be changed, but not easily. i.e. Requiring freeing of pointers, and reallocation of new memory in the shape of new dimensions.
  • Linked List. This method is similar to the previous method in that it uses dynamically allocated memory during its creation, but vastly different in terms of its flexibility. Linked Lists use a struct based architecture, with each instance of struct (or node) containing members of data related in some way, analogous to the fields contained within a database record. Linked List nodes can be inserted, deleted, searched and sorted.

Given the explicit stated requirement: "I'd like to make a 1D array 2D"
And the implied shape of your data:

patches[0][0] = "Version 1.01";
patches[0][1] = "Size 1GB";
patches[0][2] = "Is compatible";

patches[1][0] = "Version 4.01";
patches[1][1] = "Size 4GB";
patches[1][2] = "Is compatible";

Linked List stands out as the best suited option. Following is an example that could be used as the struct (or node) design for a flexibly sized and searchable list that would support what you are doing:

typedef struct patch {
     int item;
     char ver[80];
     long sz;
     char cmpat[80];
     struct patch *next;
}NODE;

Following is a brief example of inserting a node:

In main()

...
NODE *head = malloc(sizeof(*head));
if(head)
{
   insertNode(NODE **head, 1001, "Version 1.01", 1e9, "Is compatible");
   insertNode(NODE **head, 1002, "Version 4.01", 4e9, "Is compatible");
}
...

Where insertNode is defined as:

void insertNode(NODE **head, int item, char *ver, long sz, char *cmpat)
{
    //allocate new node
    NODE *new_node = malloc(sizeof(NODE));;

    new_node->item = val;
    strcpy (new_node->data, ver);
    new_node->sz = 4e9;
    strcpy(new_node->cmpat, cmpat);
    (*head) = new_node;
}
ryyker
  • 22,849
  • 3
  • 43
  • 87
0

Note that being a 3 star programmer is usually a bad thing in C. Even an array of struct patch_s { const char *version; const char *size; const char *is_compatible; }; would be way more readable here (it just suggest by itself to make it struct patch_s { unsigned long version; unsigned long long size; bool is_compatible; }).

Anyway, sure - just allocate an array of pointers and assign them. Remember that string literals are immutable in C, so use const char* pointers.

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

int main() {
    const char ***patches;
    patches = malloc(sizeof(*patches) * 2);
    if (patches == NULL) abort();
    for (int i = 0; i < 2; ++i) {
        patches[i] = malloc(sizeof(*patches[i]) * 3);
        if (patches[i] == NULL) abort();
    }

    /* -- snip --- */
    patches[0][0] = "Version 1.01";
    patches[0][1] = "Size 1GB";
    patches[0][2] = "Is compatible";

    patches[1][0] = "Version 4.01";
    patches[1][1] = "Size 4GB";
    patches[1][2] = "Is compatible";
    /* -- snip --- */

    const int k = 1;
    printf("%s - %s - %s\n", patches[k][0], patches[k][1], patches[k][2]);

    for (int i = 0; i < 2; ++i) {
        free(patches[i]);
    }
    free(patches);
}

Tested on godbolt.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111