建立复杂的字符串?

时间:2012-11-26 00:53:50

标签: c string printf

我有一堆printf()正确打印了一个我必须构建的非常复杂的字符串。

问题是我需要将该字符串存储在一个变量中(所有这些printf()的结果一起通过套接字发送它们。我很确定我需要立即发送它们 - 但如果你想让我相信那不是真的,我会打开一个小窗口。

实现这一目标的最佳方式是什么?

字符串长度是REALLY变量。我听说过sprintf()realloc(),甚至asprintf(),但我不能只看到如何将所有这些混合在一起。

这是我目前的代码:

void mostrarVariable(char *variable, void *valor) {
    printf("%s=%d\n", variable, *(int *)valor);
}

void mostrarEntradaStack(t_registro_stack *entradaStack) {
    printf("%d,%s\n", entradaStack->retorno, entradaStack->nombre_funcion);
}

void suspender(t_pcb *pcb) {
    char *mensaje = NULL;
    mensaje = strdup("1Proceso suspendido...");
    // FIXME: guardar los printf en una variable y enviarlo por la red

    printf("----------------\n\n");
    printf("ID=%d\n", pcb->id_proceso);
    printf("PC=%d\n", pcb->program_counter);
    printf("\n-- Estructura de codigo --\n");

    int indice = 0;

    // believe me: this iterates a char** printf-ing each line
    while(pcb->codigo[indice] != NULL) {
        printf("%s\n", pcb->codigo[indice++]);
    }

    printf("----------------\n");
    printf("\n-- Estructuras de datos --\n");

    // believe me: this calls mostrarVariable() for each entry in the pcb->datos dictionary
    dictionary_iterator(pcb->datos, mostrarVariable);

    printf("----------------\n\n");
    printf("-- Estructura de Stack --\n");

    // believe me: this calls mostrarEntradaStack() for each element in the stack without modifying it
    pila_hacer(pcb->stack, mostrarEntradaStack);

    printf("\n----------------\n");

    // believe me: this sends "mensaje" via a socket ("pcb->id_proceso"), and it handles the partial send()s and all of that
   // it has to be on one socket_send() to correctly send the message length to the other endpoint - the protocol pretty works
    socket_send(pcb->id_proceso, mensaje, strlen(mensaje) + 1);
}

相信我,代码目前有效,但由于mensaje只有值“1Proceso suspendido ...”,数据会在本地打印而不是发送到遥控器。

示例输出:

----------------

ID=4
PC=6

-- Estructura de codigo --
#!/home/desert69/workspaces/operativos/no-quiero/procer/pi/build/pi
# Comentario
variables a,b,c,d,e
comienzo_programa
a=1
b=2;3
c=a+b
d=c-3
f1()
f2()
e=a+c;2
imprimir a
imprimir b
imprimir c
imprimir d
imprimir e
fin_programa
comienzo_funcion f1
a=3
f3()
b=4
fin_funcion f1
comienzo_funcion f2
a=a+1
fin_funcion f2
comienzo_funcion f3
c=d
fin_funcion f3
----------------

-- Estructuras de datos --
c=159769736
d=159769776
a=159769600
b=159769696
e=159769816
----------------

-- Estructura de Stack --

----------------

对不起西班牙语的代码,但我想确定它与我正在运行的完全相同。也许以后(如果可以的话)我会尝试翻译它,但我不确定。即使很难,重要的是将每个printf()替换为 ,以便将这些输出附加到mensaje

如果您需要任何进一步的信息,请随时发表评论。

感谢。真的:)

4 个答案:

答案 0 :(得分:2)

最简单的方法是连接一堆sprintf语句。忽略错误条件,该语句返回写入的字符数。所以你基本上可以这样做:

char *bufptr = buffer;
bufptr += sprintf( bufptr, "ID=%d\n", pcb->id_proceso );
bufptr += sprintf( bufptr, "PC=%d\n", pcb->program_counter );

然后buffer包含从sprintf的连续调用构建的字符串。显然你需要确保缓冲区足够大。如果您预计有任何错误, 应该处理错误。

此外,您使用bufptr - buffer获取字符串的最终长度,这有助于了解您是否通过套接字发送此字符串。

答案 1 :(得分:0)

您可以在该缓冲区中创建大buffersprintf()个所有数据。

char buffer[20000];    // large enough
char str[500];         // temporary string holder

buffer[0] = '\0';      // clean up the buffer
sprintf( str, "----------------\n\n");            strcat( buffer, str);
sprintf( str, "ID=%d\n", pcb->id_proceso);        strcat( buffer, str);
sprintf( str, "PC=%d\n", pcb->program_counter);   strcat( buffer, str);
sprintf( str, "\n-- Estructura de codigo --\n");  strcat( buffer, str);

......等等

答案 2 :(得分:0)

乍一看看起来很琐碎。在每一步,您都要附加一个字符串或一个int。

可以将前者简化为后者
char tmp[100];
snprintf(tmp, sizeof tmp - 1, "%d", n);
append_string(tmp);  // pseudo-code

所以你需要的是一种将字符串附加到另一个字符串的方法。这可以通过strlenreallocstrcpymemcpy的组合来完成。

更大的问题是,您的dictionary_iteratorpila_hacer功能似乎不允许您将任何其他信息传递给回调。 printf并不关心,因为它只能使用全局stdout,但是如果你想将它附加到字符串,你可能需要在这里使用全局变量,所以你的回调知道了在哪里追加。

答案 3 :(得分:0)

我最终创建了一个string_concat()函数,它接收一个original字符串,一个格式和一个变量参数列表,并应用vsnprintf格式和参数,并附加到原始字符串:

编辑:好的,所以我之前的做法是错误的。我认为va_list存在问题。这是新版本:

/**
 * @NAME: string_append
 * @DESC: Agrega al primer string el segundo
 *
 * Ejemplo:
 * char *unaPalabra = "HOLA ";
 * char *otraPalabra = "PEPE";
 *
 * string_append(&unaPalabra, otraPalabra);
 *
 * => unaPalabra = "HOLA PEPE"
 */
void string_append(char** original, char* string_to_add) {
        *original = realloc(*original, strlen(*original) + strlen(string_to_add) + 1);
        strcat(*original, string_to_add);
}

/**
 * @NAME: string_concat
 * @DESC: Concatena al primer string el resultado de aplicar los parametros al
 * formato especificado
 *
 * Ejemplo:
 * char *saludo = "HOLA ";
 * char *nombre = "PEPE";
 *
 * string_concat(&saludo, "%s!", nombre);
 *
 * => saludo = "HOLA PEPE!"
 */
void string_concat(char **original, const char *format, ...) {
    size_t buffer_size = strlen(format) + 1;
    char *temporal = malloc(buffer_size);
    size_t message_length = 0;
    va_list arguments;
    va_start(arguments, format);
    while((message_length = vsnprintf(temporal, buffer_size, format, arguments)) > buffer_size - 1) {
        buffer_size *= 2;
        temporal = (char *) realloc(temporal, buffer_size);
    }
    va_end(arguments);
    temporal = (char *) realloc(temporal, message_length + 1);

    string_append(original, temporal);
}

string_append()仍在泄露记忆(由于realloc()),我希望能管理后者。


BUGGY CODE在这里开始

/**
 * @NAME: string_append
 * @DESC: Appends the second string to the first
 *
 * Example:
 * char *aWord = "Hello, ";
 * char *anotherWord = "world!";
 *
 * string_append(&aWord, anotherWord);
 *
 * => aWord = "Hello, world!"
 */
void string_append(char** original, char* string_to_add) {
    *original = realloc(*original, strlen(*original) + strlen(string_to_add) + 1);
    strcat(*original, string_to_add);
}

/**
 * @NAME: string_concat
 * @DESC: Concatenates to the first string the result of applying the arguments to 
 * the specified format
 *
 * Example:
 * char *salute = "Hello";
 * char *name = "world";
 *
 * string_concat(&salute, ", %s!", name);
 *
 * => salute = "Hello, world!"
 */
void string_concat(char **original, const char *format, ...) {
    size_t buffer_size = strlen(format) + 1;
    char *temporal = malloc(buffer_size);
    size_t message_length = 0;
    va_list arguments;
    va_start(arguments, format);
    while((message_length = vsnprintf(temporal, buffer_size, format, arguments)) > buffer_size - 1) {
        buffer_size *= 2;
        temporal = (char *) realloc(temporal, buffer_size);
    }
    va_end(arguments);
    temporal = (char *) realloc(temporal, message_length + 1);

    string_append(original, temporal);
}

BUGGY CODE结束

我之前从my assignature repository获得了string_append()

我认为它没有内存泄漏/问题,但还没有真正测试过那么多。但是对我来说是合情合好的,至少我在最初的问题中已经展示了这个例子。

所以这是我之前展示的代码的最终版本:

void suspender(t_pcb *pcb) {
    char *mensaje = NULL;
    mensaje = strdup("1Proceso suspendido...\n\n");

    string_concat(&mensaje, "----------------\n\n");
    string_concat(&mensaje, "ID=%d\n", pcb->id_proceso);
    string_concat(&mensaje, "PC=%d\n", pcb->program_counter);
    string_concat(&mensaje, "\n-- Estructura de codigo --\n");

    int indice = 0;

    while(pcb->codigo[indice] != NULL) {
        string_concat(&mensaje, "%s\n", pcb->codigo[indice++]);
    }

    string_concat(&mensaje, "----------------\n");
    string_concat(&mensaje, "\n-- Estructuras de datos --\n");

    // TODA la magia negra junta: inner functions!! (?!!?!?!)
    void mostrarVariableEnMensaje(char *variable, void *valor) {
        string_concat(&mensaje, "%s=%d\n", variable, *(int *)valor);
    }

    dictionary_iterator(pcb->datos, mostrarVariableEnMensaje);

    string_concat(&mensaje, "----------------\n\n");
    string_concat(&mensaje, "-- Estructura de Stack --\n");

    void mostrarEntradaStackEnMensaje(t_registro_stack *entradaStack) {
        string_concat(&mensaje, "%d,%s\n", entradaStack->retorno, entradaStack->nombre_funcion);
    }

    pila_hacer(pcb->stack, mostrarEntradaStackEnMensaje);

    string_concat(&mensaje, "\n----------------\n");


    socket_send(pcb->id_proceso, mensaje, strlen(mensaje) + 1);
    free(mensaje);
}