C指针问题

时间:2013-12-04 19:14:31

标签: c pointers

我正在学习C中的指针。我不明白为什么这段代码在编译过程中失败了。

#include <stdio.h>

void set_error(int *err);

int main(int argc, const char * argv[])
{
    const char *err;
    set_error(&err);
    return 0;
}


void set_error(int *err) {
    *err = "Error message";
}

7 个答案:

答案 0 :(得分:3)

您声明函数需要指向指针 - intint *)。但是你给它一个指向指针的指针 - charset_error就这样对待它。这样改变声明:

void set_error(const char ** err)

如果编译时启用了警告(GCC为-Wall),则会发出以下警告:

In function 'main':
warning: passing argument 1 of 'set_error' from incompatible pointer type [enabled by default]
set_error(&err);
^
note: expected 'int *' but argument is of type 'const char **'
 void set_error(int *err);
      ^
In function 'set_error':
warning: assignment makes integer from pointer without a cast [enabled by default]
  *err = "Error message";
       ^

答案 1 :(得分:2)

您的函数需要int *类型参数,但您要传递给它const char **类型参数 将您的函数声明更改为

void set_error(const char **err);  

答案 2 :(得分:1)

一个问题是set_error需要一个int *参数,但您传递的是char *的地址,这使其成为char **。另外,正如@Kninnug所指出的,这里有一个缓冲区覆盖问题需要处理。尝试将代码重写为:

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

void set_error(char *err, size_t errbuf_size);

int main(int argc, const char * argv[])
{
    char err_buf[1000];
    set_error(err_buf, sizeof(err_buf));
    printf("err_buf = '%s'\n", err_buf);
    return 0;
}


void set_error(char *err, size_t errbuf_size) {
    strncpy(err, "Error message", errbuf_size-1);
}

正如您在set_error的重写版本中所注意到的,另一个问题是您不能只为指针赋值并更改目标缓冲区 - 您需要使用来自标准库(这里我使用strncpy将常量“错误消息”复制到char *变量err指向的缓冲区。您可能想要熟悉这些。

分享并享受。

答案 3 :(得分:1)

你已经发现了一个关于C中字符串的重要事实的问题。 它也提出了一个关于范围界定的有趣事实。

<强> 1。 C中没有字符串这样的东西;只是一个指向字符数组的指针。

因此,您的语句*err = "Error message";是错误的,因为 derefencing err您没有达到字符串的值,但它是第一个字符。 (你无法量化C中'字符串'的值,因为在C中没有字符串这样的东西)

*err实际上是未定义的,因为尚未分配任何内容。

请注意,字符串的通常定义是const char *char *,所以我已根据您对下面的注释进行了更改:

#include <stdio.h>

int main(void){
    char * a = "hello";
    if (*a == 'h'){
       printf("it's an 'H'\n");
    }
    else{
        printf("no it isn't\n");
    }
}

您会看到*err实际上返回第一个字符的值,因为a[0] == *a

<强> 2。您无法在C

中返回指向本地范围数据的指针

set_error()有正确的意图,但注定要失败。虽然"Error message"看起来像一个值,但它实际上已经是一个指针(因为C中的字符串是指向字符数组的指针,如上所述)。

因此,考虑到(1),您可能希望能够这样做:

void set_int(int *myint) {
    *myint = 1; //works just fine because 1 is a value, not a reference
}

void set_error(char *err) {
    // doesn't work because you're trying to assign a pointer to a char
    *err = "Error message"; 

void set_error_new(char *err) {
    //doesn't work because when the function returns, "Error Message" is no longer available on the stack" (assignment works, but when you later try to get at that data, you'll segfault
    err = "Error message"; 
}

你需要采用不同的方法来解决你在C中使用所谓的“字符串”的问题。把它们想象成一个指向字符数组的指针,你就能更好地理解这些问题。另请参阅C: differences between char pointer and array

答案 4 :(得分:1)

让我们先谈谈类型。在main函数中,您将err声明为

const char *err;

当您调用set_error函数时,传递表达式&err,其类型为“指向const char *”或const char **

但是,在函数声明和定义中,将参数err声明为

int *err;

类型const char **int *不是兼容的,这就是编译器正在进行的原因。 C不允许您将一种类型的指针值分配给不同类型的指针变量(除非一个是void *,这是一种“通用”指针类型)。不保证不同的指针类型在特定平台上具有相同的大小或表示。

这就是编译器问题的来源;什么是解决方案?

在C中,像"Error message"这样的字符串文字在C ++中有类型char * 1 const char *),所以无论我赋予它什么,都需要有一个类型char *const char *。由于我们处理的是字符串文字,后者更可取(尝试修改字符串文字的内容会调用未定义的行为;某些平台会将字符串文字放在只读内存中,有些则不会)。因此,您需要对代码 2 进行以下更改:

void set_error( const char **err )
{
  *err = "Error message";
}

int main( void ) // you're not dealing with command line arguments, so for this
{                // exercise you can use `void` for your parameter list
  const char *err;
  set_error( &err ); 
  return 0;
}

请记住,C按值传递所有函数参数 ;这意味着err中的形式参数set_error是内存中的不同对象,而不是err中的实际参数main;如果代码已经

void set_error( const char *err )
{
  err = "Error message";
}

int main( void ) 
{                
  const char *err;
  set_error( err ); 
  return 0;
}

然后err中对set_error的更改不会反映在err中的变量main中。如果我们希望set_error修改errmain的值,我们需要将set_error 指针传递给err,在函数中取消引用它。由于参数 err的类型为const char **,因此表达式 *err的类型为const char *,这是我们的类型需要这项任务才能成功。

<小时/> 1。实际上,那不是真的;字符串文字的类型为“{元素数组char”,其中N是字符串中的字符数加0终止符。但是,由于不值得进入的原因,编译器会在大多数情况下将数组类型的表达式转换为指针类型的表达式。在这种情况下,字符串文字"Error message"将从“{14}元素数组char”类型的表达式转换为“指向char”的指针。

功能定义也可作为声明;我通常将被调用的函数放在调用者之前,所以我不必混淆单独的声明。这意味着我的代码“向后”或从下往上读取,但它可以节省一些维护麻烦。

答案 5 :(得分:0)

首先,您必须将函数的声明更改为

void set_error(char **err);

功能的主体是一样的。您还将err变量声明为const char *err并尝试更改它。它会产生警告。

答案 6 :(得分:-1)

1st error-->您注意到的是,您的函数需要一个指向int 的指针,并且您正在向指针传递一个指针

2nd error-->您取消引用指针并插入值“错误消息”,这是一个字符串,您的指针是指向char的指针

3rd error--> set_error(&amp; err); - &GT;这句话是错误的,因为错误本身存储了一个地址,所以不需要输入&amp; putting & means you are passing the address of the pointer *err and not the address which it is holding.所以试试这个。

include <stdio.h>

void set_error(const char* err[]);    //Function Declaration 

int main()
{
    const char* err[1000];
    set_error(err);
    printf("%s",*err);
    return 0;
}


void set_error(const char* err[])
{ 
     *err = "Error Message";
}