我在 gtk3 c 中写了一个计算器代码代码是总数,在我写 1+1+1+1 结果是 3+1 我想固定为 4

i write a code for calculator in gtk3 c the code is total numbers, in i write 1+1+1+1 the result is 3+1 i want to fix to 4

我在gtk3 c中写了一个计算器代码代码是总数,在我写1+1+1+1结果是3+1我想固定为4 calcul result

在我写 sprintf(result,"%d%s",temp,rest); 1+1+1+1 的结果是 3+1 我想得到 4 我检查 sprintf(result,"%d",temp);不正确。

申请代码:

#include<gtk/gtk.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
int calculate(int x ,int y ,char op)
{
    if(op == '+')
    {
        return x + y;
    }
    return -1;
}
char *parseMath(const char *s, char *result)
{
    int x;
    int y;
    char op;
    sscanf(s, "%d%c%d", &x,&op,&y);
    int offset = snprintf(NULL,0,"%d%c%d",x,op,y);
    const char *rest = s + offset;
    int temp = calculate(x, y, op);
    printf("%d\n",strlen(result));
    sprintf(result,"%d%s",temp,rest);

    if(rest[0]=='[=10=]')
    {
        return result;
    }else
    {
        return parseMath(result,result);
    }
}
static void on_button_press(GtkWidget *widget, gpointer buffer)
{
    const char *label = gtk_button_get_label(GTK_BUTTON(widget));
    if(*label=='=')
    {
        const char *exp = gtk_entry_buffer_get_text(buffer);
        char *result = malloc(sizeof(int)*8/3+2+strlen(exp));
        char *ans = parseMath(exp,result);
        gtk_entry_buffer_set_text(buffer,ans,-1);
        assert(result!=NULL);
        free(result);
    }else{
    guint len_buff = gtk_entry_buffer_get_length(buffer);
    gtk_entry_buffer_insert_text(buffer, len_buff, label, -1);
    }
}
int main(int argc, char **argv)
{
    gtk_init(&argc,&argv);
    GtkWidget *window;
    GtkWidget *entry;
    GtkWidget *button,*button2,*button3,*button4;
    GtkWidget *grid;
    GtkEntryBuffer *buffer;
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window),"calculator");
    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
    grid = gtk_grid_new();
    gtk_container_add(GTK_CONTAINER(window),grid);
    buffer = gtk_entry_buffer_new(NULL,-1);
    entry = gtk_entry_new();
    gtk_entry_set_buffer(GTK_ENTRY(entry), GTK_ENTRY_BUFFER(buffer));
    gtk_grid_attach(GTK_GRID(grid), entry, 0, 0, 4, 1);
    button = gtk_button_new_with_label("0");
    g_signal_connect(button, "clicked", G_CALLBACK(on_button_press), buffer);
    gtk_grid_attach(GTK_GRID(grid),button, 0, 1, 1, 1);
    button2 = gtk_button_new_with_label("+");
    g_signal_connect(button2, "clicked", G_CALLBACK(on_button_press), buffer);
    gtk_grid_attach(GTK_GRID(grid),button2, 1, 1, 1, 1);
    button3 = gtk_button_new_with_label("1");
    g_signal_connect(button3, "clicked", G_CALLBACK(on_button_press), buffer);
    gtk_grid_attach(GTK_GRID(grid),button3, 2, 1, 1, 1);
    button4 = gtk_button_new_with_label("=");
    g_signal_connect(button4, "clicked", G_CALLBACK(on_button_press), buffer);
    gtk_grid_attach(GTK_GRID(grid),button4, 3, 1, 1, 1);
    gtk_widget_show_all(window);
    gtk_main();
    return 0;
}

首先,如果您从示例中删除所有不相关的代码,我们会得到这个 MCVE:

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

int calculate(int x ,int y ,char op)
{
    if(op == '+')
    {
        return x + y;
    }
    return -1;
}

char *parseMath(const char *s, char *result)
{
    int x;
    int y;
    char op;
    sscanf(s, "%d%c%d", &x,&op,&y);
    int offset = snprintf(NULL,0,"%d%c%d",x,op,y);
    const char *rest = s + offset;
    int temp = calculate(x, y, op);
    printf("%zu\n",strlen(result));
    sprintf(result,"%d%s",temp,rest);

    if(rest[0]=='[=10=]')
    {
        return result;
    }else
    {
        return parseMath(result,result);
    }
}

int main(void)
{
    const char *exp = "1+1+1+1";
    char *result = malloc(sizeof(int)*8/3+2+strlen(exp));

    char *output = parseMath(exp, result);
    printf("output: %s\n", output);
}

这对每个人来说都更容易阅读,因为它不会分散与您的文本格式问题无关的 GTK 内容。

您应该收到此行的编译器警告:

printf("%d\n",strlen(result));

函数 strlen returns size_t 并且打印这样一个值的正确类型是 %zu,而不是 %d.

该行还包含另一个问题: 当您第一次调用该函数时,您传递 malloc 的结果,它指向未初始化的内存。访问这样的内存块会导致未定义的行为。

但这两个问题不会导致您的问题。

当您在调试器中 运行 您的程序时(您显然应该这样做!),您将看到对 parseMath 的第一次调用将为 sprintf(result,"%d%s",temp,rest); 创建正确的内容: "2+1+1"rest 将按预期指向 "+1+1"

但是事情出了问题。当您递归调用此函数时,您会注意到在您调用 sprintf(result,"%d%s",temp,rest); 创建字符串后 rest"+1" 变为 ""

如果你查看 manpage for 'sprintf' 你会发现

   C99 and POSIX.1-2001 specify that the results are undefined if a
  call to sprintf(), snprintf(), vsprintf(), or vsnprintf() would
  cause copying to take place between objects that overlap (e.g.,
  if the target string array and one of the supplied input
  arguments refer to the same buffer).  See NOTES.

除了你第一次调用 parseMath 之外,你在递归调用它时提供了两次相同的缓冲区:return parseMath(result,result);

你的计算结果的终止 0 字节 "3+1" 覆盖了 rest'+',你决定你已经完成了你的任务。

要解决该问题,您需要创建该缓冲区的副本,而不是仅仅指向 s.

最后我偶然发现了那个奇怪的表情:

char *result = malloc(sizeof(int)*8/3+2+strlen(exp));

你从哪里得到这个公式的?您要删除 2 个数字 + 1 个运算符并用 1 个数字替换它们。结果不能长于初始输入。只需使用 strlen(exp) + 1 分配内存即可。

与其他修复一起,我们得到了这个更正后的版本:

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

int calculate(int x ,int y ,char op)
{
    if(op == '+')
    {
        return x + y;
    }
    return -1;
}

char *parseMath(const char *s, char *result)
{
    int x;
    int y;
    char op;
    sscanf(s, "%d%c%d", &x,&op,&y);
    int offset = snprintf(NULL,0,"%d%c%d",x,op,y);
    char *rest = strdup(s + offset);
    int temp = calculate(x, y, op);
    printf("%zu\n",strlen(result));
    int done = rest[0]=='[=14=]';
    sprintf(result,"%d%s",temp,rest);
    free(rest);

    if(done)
    {
        return result;
    }else
    {
        return parseMath(result,result);
    }
}

int main(void)
{
    const char *exp = "1+1+1+1";
    char *result = malloc(strlen(exp) + 1);
    *result = 0;

    char *output = parseMath(exp, result);
    printf("output: %s\n", output);
}