为什么指针在这段代码中起作用而不是正常变量?

时间:2016-09-13 07:32:28

标签: c string variables pointers string-literals

在我的下面代码中,我收到了以下警告:

  
    
      

在函数'on_btn_Convert_clicked'中:|

    
  
     

警告:赋值在没有强制转换的情况下从指针生成整数[启用   默认情况下] |

     

警告:传递'gtk_label_set_text'的参数2使得指针来自   没有强制转换的整数[默认启用] |

     

|| ===构建完成:0个错误,2个警告(0分钟,1)   秒(s))=== |

如果我按原样运行程序,它将打开GUI但有问题的按钮会在按下时导致分段错误并使程序崩溃。

#include <stdlib.h>
#include <stdio.h>
//include gtk headers
#include <gtk/gtk.h>

//define pointer variable names
GtkWidget  *plblFileName;
GtkWidget  *pbtnConvert;
GtkWidget  *pbtnFileChooser;


//prototype functions
char on_btn_Convert_clicked();

char on_btn_Convert_clicked()
{
   //define variables
   char hello;

   hello = "hello!";

   gtk_label_set_text(GTK_LABEL(plblFileName), hello);
   return 0;
}

//start main loop
int main( int    argc,
      char **argv )
{
    GtkBuilder *builder;
    GtkWidget  *window;
    GError     *error = NULL;

    //Init GTK+
    gtk_init( &argc, &argv );

    //Create new GtkBuilder object
    builder = gtk_builder_new();
    //Load UI from file. If error occurs, report it and quit application.
    //Replace "tut.glade" with your saved project.
    if( ! gtk_builder_add_from_file( builder, "testGTK.ui", &error ) )
    {
        g_warning( "%s", error->message );
        g_free( error );
        return( 1 );
    }

    //Get main window pointer from UI
    window = GTK_WIDGET( gtk_builder_get_object( builder, "windowMain" ) );

    // get pointer to the label and button
    plblFileName = GTK_WIDGET(gtk_builder_get_object(builder, "lbl_FileName"));
    pbtnConvert = GTK_WIDGET(gtk_builder_get_object(builder, "btn_Convert"));
    pbtnFileChooser = GTK_WIDGET(gtk_builder_get_object(builder, "btn_Choose"));

    //connect the button with its signal
    g_signal_connect(G_OBJECT(pbtnConvert), "clicked", G_CALLBACK(on_btn_Convert_clicked), NULL);

    //Destroy builder, since we don't need it anymore
    g_object_unref( G_OBJECT( builder ) );

    //Show window. All other widgets are automatically shown by GtkBuilder
    gtk_widget_show( window );

    //Start main loop
    gtk_main();

    return( 0 );
}

但是,如果我制作变量&#39;你好&#39;一个指针,然后错误消失,一切正常。

像这样:

char on_btn_Convert_clicked()
{
   //define variables
   char *hello;

   hello = "hello!";

   gtk_label_set_text(GTK_LABEL(plblFileName), hello);
   return 0;
}

我不明白指针,即指向内存中某个位置的对象如何能够等于&#34;你好&#34;还是这样工作?

任何人都可以向我解释为什么&#39; char hello&#39;变量需要是一个指针(*),而不能只是一个字符串或&#39; char []&#39 ;?

最后,你能总结一下为什么这个工作与普通char变量的版本有关吗?

3 个答案:

答案 0 :(得分:5)

因为在代码的第一部分

char hello;
hello = "hello!";

是错误的,因为您的编译器已经警告过您。

"Hello!"形式的string literal返回指向第一个元素的指针,即字符串中第一个元素的地址,并且不能存储到char中。你需要一个char *来持有它。

或者,您可以使用数组char hello[] = "hello!";。这会创建一个数组并使用字符串文字“hello!”初始化数组,这也应该可以正常工作,但是简单的(标量)char无论如何都不会起作用。

答案 1 :(得分:3)

"hello"之类的常量字符串文字实际上是一个包含六个字符的数组('h''e''l''l''o'和终结者'\0')。当你使用它时,它可以衰减到指向它的第一个元素的指针。

就像拥有一个实际的数组:

char hello_array[6] = { 'h', 'e', 'l', 'l', 'o', '\0' };

然后将其分配给像

这样的指针
char *hello = &hello_array[0];

以上就是你做什么时基本上发生的事情

char *hello = "hello";

当你有

char hello = "hello";

它就像在做

char hello = &hello_array[0];

这根本不起作用。调用函数时它是相同的,它期望类型为char *的参数,并传递类型为char的参数。这两种类型长期不一样。

解释它的另一种方式可能是你想到这样的事情:变量是存储值的地方。如果您有char类型的变量,则可以存储单个字符。当你有一个指向一个字符的指针时,你可以准确地存储它,一个指针指向一个字符(实际上是一个内存地址)。

例如,假设我们有

char a = 'a';
char *b = &a;

有点图形化,可以这样看:

                +-----+
The variable a: | 'a' |
                +-----+
                ^
                |
                +-----------------------+
The variable b: | Address of variable a |
                +-----------------------+

变量b 指向变量a

如果打印两种类型的尺寸,差异应该非常明显:

printf("sizeof(char) = %zu\n", sizeof(char));
printf("sizeof(char *) = %zu\n", sizeof(char *));

第一行应该说char的大小为1(顺便说一句,在C规范中指定它始终为1)。指针的大小应为4(在32位系统上)或8(在64位系统上)。

答案 2 :(得分:1)

@SouravGhosh给你一个很好的答案,这里有一个建议:

不要使用像plblFileName这样的全局字符:

char on_btn_Convert_clicked()
{
   //define variables
   char *hello;

   hello = "hello!";

   gtk_label_set_text(GTK_LABEL(plblFileName), hello);
   return 0;
}

而是为此信号使用正确的原型("clicked"

void on_btn_Convert_clicked(GtkButton *button, gpointer user_data)
{
   //define variables
   char *hello;

   hello = "hello!";

   gtk_label_set_text(GTK_LABEL(user_data), hello);
}

并连接传递标签的信号:

g_signal_connect(G_OBJECT(pbtnConvert), "clicked", 
                 G_CALLBACK(on_btn_Convert_clicked), plblFileName);