Динамическое добавление элементов в массив C

Я пытаюсь создать функцию, которая принимает строку символов и предоставляет список этих символов, разделенных токеном.

Вот что у меня есть на данный момент:

char * decode_args(char arguments[]){
  char* token = strtok(arguments, "00");
  while (token != NULL){
    printf("%s\n", token);
    token = strtok(NULL, "00");
  }
  return 0;
}

Эта функция печатает желаемые значения, которые я ищу. Например:

>decode_args("77900289008764")
779
289
8764

Следующим шагом является создание массива, который можно использовать в команде execv. Аргументы должны быть массивом. Пример здесь. Я новичок, поэтому даже не знаю, правильное ли слово «массив». Какой тип данных должен быть создан и как это сделать, чтобы я мог вызвать execv с аргументами, которые в настоящее время печатаются в списке?


person lex449    schedule 26.02.2020    source источник
comment
Связанный пример содержит правильный тип аргументов: char * ls_args[], т.е. вам нужен массив указателей на char. Основная проблема в вашем случае - узнать количество аргументов перед определением массива. Имейте в виду, что strtok изменяет начальную строку. Это может затруднить определение количества аргументов вначале и их последующее копирование в этот массив.   -  person Gerhardh    schedule 26.02.2020
comment
Отвечает ли это на ваш вопрос? Разобрать строку в argv / argc   -  person Ctx    schedule 26.02.2020
comment
Хм, ладно, похоже, ваш разделитель будет 00. Обратите внимание, что это не то, что делает strtok(..., "00");; strtok() поддерживает только односимвольные разделители (хотя и несколько), поэтому это эквивалентно strtok(..., "0");. Вы можете использовать strstr() или подобное.   -  person Ctx    schedule 26.02.2020


Ответы (2)


Для начала позвольте мне кое-что рассказать о хранении и строках.

Есть 3 основных типа хранения. Автоматический, динамический, статический. А статический обычно делится на два: только для чтения и для чтения-записи. Скоро вам пригодятся динамические и статические.

Автоматические переменные - это параметры функции и локальные переменные. Когда вы вызываете функцию, они помещаются в стек, а когда функция возвращается, они раскручиваются.

Динамический - это тот, который вы выделяете во время выполнения с семейством malloc. Вот как мы создаем динамический массив. И вам нужно вернуть этот источник, когда вы закончите с free. Если вы этого не сделаете, это называется утечкой памяти, и вы можете проверить утечку памяти с помощью инструмента valgrind наряду с другими ошибками памяти. Это очень полезно для занятий системным программированием.

А статические - это те, которые остаются там на протяжении всего срока действия программы. Если вы определите глобальную переменную или static int i = 42, она создаст статическую переменную для чтения и записи, чтобы вы могли ее изменить. А теперь уловка.

void foo() {
   char *string1 = "hello, world" //static read-only
   char string2[] = "hello, world" //automatic
}

Поэтому, если вы попытаетесь изменить string1, вы получите ошибку сегментации, но это нормально, чтобы изменить string2. Я не знаю, почему вы не получаете ошибки сегментации, выполняя decode_args("77900289008764"), но я попал на свою машину. : D

Теперь C-струны. Они оканчиваются нулем, что означает, что каждая строка имеет конец (char) 0 символов, который говорит, что это конец строки. strtok в основном заменяет шаблон символом NULL, чтобы у вас было несколько подстрок вместо одной. Итак, из вашего примера он преобразует "77900289008764 NULL" в "779 NULL 289 NULL 8764 NULL"

Итак, на вашем месте я бы подсчитал встречи с «00» в строке и выделил бы указатель на столько символов. Что-то вроде:

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

char ** decode_args(char *arguments, char *delim) {
    int num_substrings = 1; // Note that C don't initialize with 0 like java etc.
    int len_delim = strlen(delim);

    for (int i = 0;
            arguments[i] != '\0' && arguments[i + 1] != '\0'; // Any of last 2 chars are terminator?
            ++i)
        if (strncmp(arguments + i /* same as &arguments[i] */, delim, len_delim) == 0)
            ++num_substrings;

    char **result = (char **) malloc(sizeof(char *) * (num_substrings + 1));
    int i = 0;
    char* token = strtok(arguments, delim);

    while (token != NULL){
        result[i] = token;
        ++i;
        token = strtok(NULL, delim);
    }

    result[i] = NULL; //End of results. execv wants this as I remember

    return result;
}
int main(int argc, char *argv[])
{
    char str[] = "foo00bar00baz";
    char **results = decode_args(str, "00");

    for (int i = 0; results[i] != NULL; ++i) {
        char *result = results[i];
        puts(result);
    }

    free(results);

    return 0;
}
person bca    schedule 26.02.2020

Попробуйте что-то вроде этого:

#define MAX_ARGUMENTS 10

int decode_args(char arguments[], char ** pcListeArgs)
{
    int iNumElet = 0;
    char* token = strtok(arguments, "00");

    while ((token != NULL) && (iNumElet < MAX_ARGUMENTS -1)) 
    {
        size_t len = strlen(token);

        pcListeArgs [iNumElet] = (char*) calloc (len+1, sizeof (char));
        memset(pcListeArgs [iNumElet], 0, len+1); // reset content
        memcpy(pcListeArgs [iNumElet], token, len); // copy data

        token = strtok(NULL, "00");
        iNumElet++;
    }

    if ( iNumElet >= MAX_ARGUMENTS)
        return -1;

    return iNumElet;
}

И в главном:

int main() {

    char *pListArgs[MAX_ARGUMENTS];

    char args[] = "77900289008764";

    int iNbArgs = decode_args (args, pListArgs);

    if ( iNbArgs > 0)
    {
        for ( int i=0; i<iNbArgs; i++)
            printf ("Argument number %d = %s\n", i, pListArgs[i]);

        for ( int i=0; i<iNbArgs; i++)
            free (pListArgs[i]);
    }

    return 0;
}

вывод:

введите описание изображения здесь

person Landstalker    schedule 26.02.2020