Заменить $$ в строке с идентификатором из getpid ()? - PullRequest
0 голосов
/ 15 ноября 2018

Если у меня есть строка, подобная следующей:

char* exampleString = "test$$";

Допустим, getpid() возвращает 1587.

Как я могу заменить $$ в строке результатом getpid() так, чтобы результатом была строка "test1587"?

Ответы [ 2 ]

0 голосов
/ 15 ноября 2018

Вы не можете выполнить прямую подстановку, потому что ваша строка (массив символов) недостаточно длинна для хранения pid, и, конечно, если она объявлена ​​как строковый литерал, она также не является изменяемой.

Есть несколько способов, которыми вы могли бы воспользоваться этим, но вот довольно элегантный:

/* Modify the existing string to be a pattern string for snprintf */
int len = strlen(exampleString) - 1; /* Can you see why I might do this? */
char* formatString = strdup(exampleString); /* Because we can't modify a literal */
int newLen = len + 12; /* How about this? */
char *pidString = malloc(newLen);
int i;
for (i = 0; i < len; i++) {
  if (formatString[i] == '$' && formatString[i+1] == '$') {
    formatString[i] = '%';
    formatString[i+1] = 'd';
    break;
  }
}
snprintf(pidString, newLen - 1, formatString, getpid());

Можете ли вы следить за тем, как это работает?

Как бы вы улучшили это, чтобы изящно завершиться неудачей, если exampleStringне содержит $$?

0 голосов
/ 15 ноября 2018

Поскольку "test$$" является неизменным, и указатель на него должен быть лучше char const* вместо char*, вам придется скопировать его в массив, где вы можете заменить "$$".

Возможное решение:

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

#include <unistd.h>

int main(void)
{
    char const *input = "foo$$bar";
    pid_t pid = 1234;

    size_t format_length = strlen(input);
    char *format = calloc(format_length + 2, 1);
    if (!format) {
        fputs("Couldn't allocate memory :(\n\n", stderr);
        return EXIT_FAILURE;
    }

    // copy input to format replacing "$$" with "%ld" in the process
    bool replacement_done = false;
    for (size_t i = 0; i < format_length + replacement_done; ++i) {
        if (!replacement_done && i + 1 < format_length &&
            input[i] == '$' && input[i + 1] == '$')
        {
            format[  i] = '%';  // just
            format[++i] = 'l';  // being
            format[++i] = 'd';  // safe.
            replacement_done = true;
            continue;
        }

        format[i] = input[i - replacement_done];
    }

    if (!replacement_done) {
        free(format);
        fputs("Nothing to do :(\n\n", stderr);
        return EXIT_FAILURE;
    }

    char *result = malloc(1);
    if (!result) {
        free(format);
        fputs("Couldn't allocate memory :(\n\n", stderr);
        return EXIT_FAILURE;
    }

    // there is no guesswork needed, snprintf() will tell the needed size
    int bytes_needed = snprintf(result, 1, format, (long)getpid());
    if (bytes_needed < 0) {
        free(format);
        free(result);
        fputs("snprintf() failed :(\n\n", stderr);
        return EXIT_FAILURE;
    }

    char *temp = realloc(result, ++bytes_needed);
    if (!temp) {
        free(format);
        free(result);
        fputs("Couldn't allocate memory :(\n\n", stderr);
        return EXIT_FAILURE;
    }
    result = temp;

    int written = snprintf(result, bytes_needed, format, (long)getpid());  // long should be big enough
    if(written < 0 || written >= bytes_needed ) {
        free(format);
        free(result);
        fputs("snprintf() failed :(\n\n", stderr);
        return EXIT_FAILURE;
    }

    puts(result); // done.

    free(format);
    free(result);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...