Инициализация массива из текстовой строки


У меня есть блок текста, где несколько массивов печатаются, с именем и значения:

VAL1=10 20 30 40 50

VAL2=4 8 15 16 23 42

У меня есть функция, которая ищет имя параметра, и задает массив из этих значений:

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;
}

Называется так:

FetchValueArray(source, "VAL1=", "%d", 5, val1array, sizeof(val1array[0]);
FetchValueArray(source, "VAL2=", "%d", 6, val1array, sizeof(val1array[0]);

Это с сайте StackOverflow вопрос. В качестве ответа написал, это работает, но это не безопасно. Если я называю его рассчитывать , что выше, чем размер массива, я приведет к повреждению памяти. Я пытаюсь обернуть мою голову вокруг этого и тяжело. Как я могу иметь функцию, которая будет устанавливать значения в фиксированный массив и быть "безопасным"?



291
4
задан 5 октября 2011 в 11:10 Источник Поделиться
Комментарии
2 ответа

Я не совсем уверен, что вы просите, но я думаю, вы ищете решение, похожее на это (не компилируется и не проверял):

#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;
}

Редактировать:
Относительно проверкой границ массива. Сначала вы должны решить, будет ли это на самом деле ваше беспокойство, или если вы должны оставить его до абонента. Чаще всего, вам документировать каждый параметр .H-файл и государства, как функция должна быть вызвана. Если кто-то все равно решает вызвать его неправильные параметры, то это их вина. Вот как большинство функций c работы и в данном конкретном случае, я бы порекомендовал.

Так как C не хранит размер массива вместе с массива как единый тип данных, вы не можете действительно передать массив размера "благополучно" между абонентом и функция, звонящий с знаний о размере, так что вы просто должны доверять программист, пишущий абонент.

Вы могли бы написать что-то вроде этого

bool FetchValueArray(char dest[25], ...

но до сих пор нет гарантий стандартный, что это безопасно. Некоторые компиляторы будут бросать предупреждение, если вы попытаетесь что-нибудь передать, но фиксированной char массив из 25 элементов данной функции, но они не должны. И мы потеряем универсальный тип, так что это не полезно.

Вы могли бы сделать что-то подобное, но я бы не рекомендовал его:

#define SIZE 25

typedef union
{
char char_array[SIZE];
int int_array[SIZE];
float float_array[SIZE];

} GenericSafeArray_t;

Это позволит выделить размер*оператор sizeof(поплавок), так как поплавок случилось, будет самой большой тип. Так что память-неэффективны и не особенно гибкий либо.

4
ответ дан 5 октября 2011 в 01:10 Источник Поделиться

Сейчас есть некоторые трюки, если у вас есть реальный массив:

int   data[5];
sizeof(data) => sizeof(int) * 5
sizeof(data)/sizeof(data[0]) => Number of elements in the array
Note this is also safe if the array has zero elements
As sizeof is evaluated at compile time not run-time.

так что если у вас есть реальный массив, то вы можете вызвать метод такой:

int    val1array[5];
FetchValueArray(source, "VAL1=", "%d",
sizeof(val1array)/sizeof(val1array[0]),
val1array,
sizeof(val1array[0])
);

Беда это, кажется, работает и компилируется, если val1array является указателем на массив. К сожалению, в этом sizeof(val1array) вернет размер указателя, и конюх, вы можете не передавать массивы как параметры функций в C (они распадаются на указатели) нет никакого способа, чтобы определить размер массива на другой стороне функции.

Поэтому (правило) если вы когда-нибудь передать массив в качестве параметра, то вы должны также передать ее размер, используя хитрость, и передайте эту информацию с массива во все времена.

2
ответ дан 5 октября 2011 в 04:10 Источник Поделиться