patterncMinor
Array initialization from text string
Viewed 0 times
fromarraytextinitializationstring
Problem
I have a block of text where several arrays are printed out, with a name and values:
VAL1=10 20 30 40 50
VAL2=4 8 15 16 23 42
I have a function that looks for the value name, and sets an array of these values:
Called thus:
This is from a StackOverflow question. As the answerer wrote, it works, but it's not safe. If I call it with a
VAL1=10 20 30 40 50
VAL2=4 8 15 16 23 42
I have a function that looks for the value name, and sets an array of these values:
bool FetchValueArray(char* source, char* name, char* typeFormat, int count, void* destination, size_t destElementSize)
{
int i;
char *t;
t=strstr(source,name);
if (t)
if (destination != NULL)
{
for (i = 0;i < count;i++)
sscanf(t, typeFormat, (char*)destination + destElementSize * i);
return true;
}
return false;
}Called thus:
FetchValueArray(source, "VAL1=", "%d", 5, val1array, sizeof(val1array[0]);
FetchValueArray(source, "VAL2=", "%d", 6, val1array, sizeof(val1array[0]);This is from a StackOverflow question. As the answerer wrote, it works, but it's not safe. If I call it with a
count that is higher than the size of the array, I will corrupt the memory. I'm trying to wrap my head around this one and having a tough time. How can I have a function that will set values to a fixed array and be "safe"?Solution
I'm not quite sure what you are asking for, but I guess you are looking for a solution similar to this (not compiled nor tested):
EDIT:
Regarding array bounds checking. First you have to decide whether this is actually your concern or if you should leave it up the caller. Most commonly, you document every parameter in the .h file and state how the function should be called. If someone still decides to call it with incorrect parameters, it is then their own fault. That's how most C functions work and in this particular case, that's what I would recommend.
Since C does not store the array size together with the array as one single data type, you can't really pass an array size "safely" between the caller and a function, the caller is the one with the knowledge about the size, so you simply have to trust the programmer writing the caller.
You could write something like this
but there are still no guarantees by the standard that this is safe. Some compilers will toss a warning if you try to pass anything but a fixed char array of 25 items to this function, but they don't have to. And we'd lose the generic type, so it isn't helpful.
You could do something like this, but I would not recommend it:
This will allocate
#include /* sscanf */
#include /* NULL */
#include /* C99 bool type */
typedef enum
{
TYPE_CHAR = 'c',
TYPE_INT = 'd',
TYPE_FLOAT = 'f',
// etc
} Type_t;
/* I placed destination first to use the same parameter order as standard library
functions (strstr for example). Note the const correctness for read-only parameters. */
bool FetchValueArray (void* dest,
const char* source,
const char* name,
size_t count,
Type_t type)
{
const char* strptr; /* Some string pointer (not sure what it does) */
BOOL is_found; /* Is the name found? */
if(dest == NULL) /* No need to do anything if this parameter is NULL */
{
return false;
}
strptr = strstr(source, name);
is_found = strptr != NULL; /* Boolean arithmetic */
if(is_found)
{
size_t i;
size_t item_size;
const char format[2] = {'%', (char)type};
switch(type)
{
case TYPE_CHAR: item_size = 1; break;
case TYPE_INT: item_size = 4; break;
case TYPE_FLOAT: item_size = 4; break;
}
for(i=0; i<count; i++)
{
sscanf(strptr, format, (char*)dest + item_size*i);
}
}
return is_found;
}EDIT:
Regarding array bounds checking. First you have to decide whether this is actually your concern or if you should leave it up the caller. Most commonly, you document every parameter in the .h file and state how the function should be called. If someone still decides to call it with incorrect parameters, it is then their own fault. That's how most C functions work and in this particular case, that's what I would recommend.
Since C does not store the array size together with the array as one single data type, you can't really pass an array size "safely" between the caller and a function, the caller is the one with the knowledge about the size, so you simply have to trust the programmer writing the caller.
You could write something like this
bool FetchValueArray(char dest[25], ...but there are still no guarantees by the standard that this is safe. Some compilers will toss a warning if you try to pass anything but a fixed char array of 25 items to this function, but they don't have to. And we'd lose the generic type, so it isn't helpful.
You could do something like this, but I would not recommend it:
#define SIZE 25
typedef union
{
char char_array[SIZE];
int int_array[SIZE];
float float_array[SIZE];
} GenericSafeArray_t;This will allocate
SIZE*sizeof(float), since float happend to be the largest type. So it is memory-ineffective and not particularly flexible either.Code Snippets
#include <stdio.h> /* sscanf */
#include <stddef.h> /* NULL */
#include <stdbool.h> /* C99 bool type */
typedef enum
{
TYPE_CHAR = 'c',
TYPE_INT = 'd',
TYPE_FLOAT = 'f',
// etc
} Type_t;
/* I placed destination first to use the same parameter order as standard library
functions (strstr for example). Note the const correctness for read-only parameters. */
bool FetchValueArray (void* dest,
const char* source,
const char* name,
size_t count,
Type_t type)
{
const char* strptr; /* Some string pointer (not sure what it does) */
BOOL is_found; /* Is the name found? */
if(dest == NULL) /* No need to do anything if this parameter is NULL */
{
return false;
}
strptr = strstr(source, name);
is_found = strptr != NULL; /* Boolean arithmetic */
if(is_found)
{
size_t i;
size_t item_size;
const char format[2] = {'%', (char)type};
switch(type)
{
case TYPE_CHAR: item_size = 1; break;
case TYPE_INT: item_size = 4; break;
case TYPE_FLOAT: item_size = 4; break;
}
for(i=0; i<count; i++)
{
sscanf(strptr, format, (char*)dest + item_size*i);
}
}
return is_found;
}bool FetchValueArray(char dest[25], ...#define SIZE 25
typedef union
{
char char_array[SIZE];
int int_array[SIZE];
float float_array[SIZE];
} GenericSafeArray_t;Context
StackExchange Code Review Q#5192, answer score: 4
Revisions (0)
No revisions yet.