Asked  7 Months ago    Answers:  5   Viewed   66 times

I have a program that reads a "raw" list of in-game entities, and I intend to make an array holding an index number (int) of an indeterminate number of entities, for processing various things. I would like to avoid using too much memory or CPU for keeping such indexes...

A quick and dirty solution I use so far is to declare, in the main processing function (local focus) the array with a size of the maximum game entities, and another integer to keep track of how many have been added to the list. This isn't satisfactory, as every list holds 3000+ arrays, which isn't that much, but feels like a waste, since I'll possible use the solution for 6-7 lists for varying functions.

I haven't found any C (not C++ or C#) specific solutions to achieve this. I can use pointers, but I am a bit afraid of using them (unless it's the only possible way).

The arrays do not leave the local function scope (they are to be passed to a function, then discarded), in case that changes things.

If pointers are the only solution, how can I keep track of them to avoid leaks?

 Answers

82

I can use pointers, but I am a bit afraid of using them.

If you need a dynamic array, you can't escape pointers. Why are you afraid though? They won't bite (as long as you're careful, that is). There's no built-in dynamic array in C, you'll just have to write one yourself. In C++, you can use the built-in std::vector class. C# and just about every other high-level language also have some similar class that manages dynamic arrays for you.

If you do plan to write your own, here's something to get you started: most dynamic array implementations work by starting off with an array of some (small) default size, then whenever you run out of space when adding a new element, double the size of the array. As you can see in the example below, it's not very difficult at all: (I've omitted safety checks for brevity)

typedef struct {
  int *array;
  size_t used;
  size_t size;
} Array;

void initArray(Array *a, size_t initialSize) {
  a->array = malloc(initialSize * sizeof(int));
  a->used = 0;
  a->size = initialSize;
}

void insertArray(Array *a, int element) {
  // a->used is the number of used entries, because a->array[a->used++] updates a->used only *after* the array has been accessed.
  // Therefore a->used can go up to a->size 
  if (a->used == a->size) {
    a->size *= 2;
    a->array = realloc(a->array, a->size * sizeof(int));
  }
  a->array[a->used++] = element;
}

void freeArray(Array *a) {
  free(a->array);
  a->array = NULL;
  a->used = a->size = 0;
}

Using it is just as simple:

Array a;
int i;

initArray(&a, 5);  // initially 5 elements
for (i = 0; i < 100; i++)
  insertArray(&a, i);  // automatically resizes as necessary
printf("%dn", a.array[9]);  // print 10th element
printf("%dn", a.used);  // print number of elements
freeArray(&a);
Tuesday, June 1, 2021
 
van_folmert
answered 7 Months ago
47

According to declaration int** test; , test is pointer to pointer, and the code pice allocating memory for a matrix of int values dynamically using malloc function.

Statement:

test = (int **)malloc(k * sizeof(int*));
    //                ^^------^^-------
    //  allocate for  k  int*  values    

Allocate continue memory for k pointers to int (int*). So suppose if k = 4 then you gets something like:

 temp      343  347  351  355
+----+    +----+----+----+----+
|343 |---►| ?  | ?  | ?  |  ? |
+----+    +----+----+----+----+

I am assuming addresses are of four bytes and ? means garbage values.

temp variable assigned returned address by malloc, malloc allocates continues memory blocks of size = k * sizeof(int**) that is in my example = 16 bytes.

In the for loop you allocate memory for k int and assign returned address to temp[i] (location of previously allocated array).

test[i] = (int*)malloc(k * sizeof(int)); //Initialize all the values
//                     ^^-----^^----------
//       allocate for  k   int  values    

Note: the expression temp[i] == *(temp + i). So in for loop in each iterations you allocate memory for an array of k int values that looks something like below:

   First malloc                     For loop   
  ---------------                  ------------------
       temp
      +-----+
      | 343 |--+
      +-----+  |
               ▼                    201   205   209    213  
        +--------+                +-----+-----+-----+-----+
 343    |        |= *(temp + 0)   |  ?  |  ?  |  ?  | ?   |  //for i = 0
        |temp[0] |-------|        +-----+-----+-----+-----+
        | 201    |       +-----------▲
        +--------+                  502   506  510    514
        |        |                +-----+-----+-----+-----+
 347    |temp[1] |= *(temp + 1)   |  ?  |  ?  |  ?  | ?   |  //for i = 1
        | 502    |-------|        +-----+-----+-----+-----+
        +--------+       +-----------▲
        |        |                  43    48    52    56
 351    | 43     |                +-----+-----+-----+-----+
        |temp[2] |= *(temp + 2)   |  ?  |  ?  |  ?  | ?   |  //for i = 2
        |        |-------|        +-----+-----+-----+-----+
        +--------+       +-----------▲
 355    |        |
        | 9002   |                 9002  9006   9010 9014
        |temp[3] |                +-----+-----+-----+-----+
        |        |= *(temp + 3)   |  ?  |  ?  |  ?  | ?   |  //for i = 3
        +--------+       |        +-----+-----+-----+-----+
                         +-----------▲

Again ? means garbage values.

Additional points:

1) You are casting returned address by malloc but in C you should avoid it. Read Do I cast the result of malloc? just do as follows:

test = malloc(k* sizeof(int*));
for (i = 0; i < k; i++){
    test[i] = malloc(k * sizeof(int));
}

2) If you are allocating memory dynamically, you need to free memory explicitly when your work done with that (after freeing dynamically allocated memory you can't access that memory). Steps to free memory for test will be as follows:

for (i = 0; i < k; i++){
    free(test[i]);
}
free(test);

3) This is one way to allocate memory for 2D matrix as array of arrays if you wants to allocate completely continues memory for all arrays check this answer: Allocate memory 2d array in function C

4) If the description helps and you want to learn for 3D allocation Check this answer: Matrix of String or/ 3D char array

Sunday, August 1, 2021
 
Moose
answered 4 Months ago
33

You have to look at the way how the EntityCollection entities is filled up. If retrieving using RetrieveMultiple, then Pull the minimal fields may be the native Name field & PK Id field will come by default. This way not the whole entity will be updated back.

Avoid using AllColumns = true. Use ColumnSet to get minimal fields needed for validation.

ColumnSet = new ColumnSet("field_needed"),

Next, assign only the necessary fields like below inside loop.

foreach (var entity in entities.Entities)
    {
        UpdateRequest updateRequest = new UpdateRequest { Target = entity };

        entity.Attributes["field_to_update"] = "field_value";

        multipleRequest.Requests.Add(updateRequest);
    }

My answer will help you to understand what went wrong & correcting it. Like Nicknow said, you can assign fresh entity to solve issue.

Tuesday, October 5, 2021
 
hoof_hearted
answered 2 Months ago
100

You just need to create one connection record. One thing to note is I don't think you need to set the typecodes as you are doing above. Just setting the logical names in the entity references should be enough. Here is the sample from the SDK:

Connection newConnection = new Connection
{
    Record1Id = new EntityReference(Account.EntityLogicalName,
        _accountId),
    Record1RoleId = new EntityReference(ConnectionRole.EntityLogicalName,
        _connectionRoleId),                             
    Record2RoleId = new EntityReference(ConnectionRole.EntityLogicalName,
        _connectionRoleId),                            
    Record2Id = new EntityReference(Contact.EntityLogicalName,
        _contactId)
};
_connectionId = _serviceProxy.Create(newConnection);
Thursday, October 21, 2021
 
Organis
answered 1 Month ago
21

You have allocated space for dcArrPtr, but didn't allocate every object in this array. You must do following:

Server::Server(int x, int y, int count)
{
  dcPtr = new DizzyCreature[count];

  dcArrPtr = new DizzyCreature*[count];
  for ( int i = 0; i < count; i++ ) {
    dcArrPtr[ i ] = new DizzyCreature;
  }
  _count = count;
}

Server::~Server(void)
{
  for ( int i = 0; i < count; i++ ) {
    delete dcArrPtr[ i ];
  }
  delete[] *dcArrPtr;
  delete[] dcPtr;
}
Saturday, November 27, 2021
 
user692942
answered 3 Days ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share