【问题标题】:Conflicting point between char array and char pointer with returning the adresschar数组和char指针之间的冲突点与返回地址
【发布时间】:2019-07-10 11:19:18
【问题描述】:

目的:我的主要目的是在某种函数中创建一个字符串,它应该返回一个地址,通过使用 main 中的字符串返回地址。 但是我学习了 char 数组和 char 指针实际上用于相同的目的。

如果我们认为这是真的,我们有这些声明:

char *arrchar arr[10]*(arr+9)=arr[10] 不是吗?

应用程序 1工作。
应用程序 2工作正常。

应用 1:

#include <stdio.h> 
char *foo(char arr[]);

int main(void)
{

    char example[10];
    example=foo(example);
    printf("%s\n",example);

    return 0;   
}
char *foo(char arr[])
{
    arr[10]="attempt";

    return arr;
}

应用 2:


#include <stdio.h>
char *foo(char*);
int main(void)
{
    char *example;
    example=foo(example);
    printf("%s\n",example);
    return 0;
}
char *foo(char* arr)
{
    arr="attempt";
    return arr;
}

【问题讨论】:

  • 如果您声明 char arr[10];(10 个元素,编号为 0 到 9),则有效索引为 09,而不是 10。所以*(a + 9) 有效,但*(a + 10) 无效。
  • 对不起,这是真的,我要编辑它。
  • 如果您尝试使用 gcc 编译器编译您的第一个代码示例,您将收到以下错误 > 错误:赋值给数组类型的表达式,发生在第 8 行 example=foo(example);跨度>
  • 但是将字符串分配给 char (无论是 arr[0]、arr[9] 还是 arr[10]——它们都是数组的元素,而不是数组),不会有道理。您想改用 strcpy() 或 strncpy() 将字符串复制到数组:strncpy(arr, "attempt", 10);.
  • 我知道这是可能的,但我想通过从函数返回地址来解决这个问题。

标签: c arrays function pointers char


【解决方案1】:

您的代码将在两个段中调用 undefined behavior。 (即使您已经观察到代码2 工作,它只是似乎工作。实际上是一个failure is lurking,并且可以显示没有警告。)

进行这些更正以解决该问题,并查看 cmets 以获得解释:

代码 1

//int main(void){
int main(void){//int main(void) is minimum prototype for main function.

    //char example[10];               // this will invoke undefined behavior
    char example[10] = {"something"}; // 'example' initialized with content,
                                      // thus averting undefined behavior
    //example=foo(example);
    strcpy (example, foo(example));  // char array is not assignable using `=`
                                     // use strcpy to transfer result of "foo"
    printf("%s\n",example);

    return 0;   
}
char *foo(char arr[]) //note: char arr[] decays into char *arr
{
    //char arr[10]="attempt"; // Error: redefinition of 'arr' with a 
                              // different type: char[10] vs char *

    arr = "attempt"; //because char [] decays into char *, 'arr' is usable as is.

    return arr;
}

在 cmets 中回答您的问题:为什么要使用 strcpy 函数 [在变量之后 示例 是已初始化] 不是未定义的行为
首先,了解 C 字符串的定义很重要。 (C string definition is found here。)
变量example的原始形式,即初始化:

char example[10];  

可以包含任何东西。例如:

|%|h|8|\#|d|o|-|~|*|U|?|?|?|?|
//                   ^end of memory for 'example`
// note that the character in example[9] == 'U', not NULL, therefore, not a C string.    

这将导致函数strcpy() 失败。初始化保证可预测的结果:

char example[10] = {"something"};//properly initialized
|s|o|m|e|t|h|i|n|g|0|?|?|?|?|
//                  ^end of memory for 'example`
//or
char example[10] = {0};          //also properly initialized
|0|0|0|0|0|0|0|0|0|0|?|?|?|?|
//                  ^end of memory for 'example`
(This would require an extra step to place proper content.):
strcpy(example, "something");

需要代码2的唯一调整就是在使用前先初始化指针:(见必须初始化指针的原因here。)

char *foo(char*);

//int main(void){
int main(void){//int main(void) is minimum prototype for main function.
{
    //char *example; // passing this will envoke undefined behavior
    char *example = NULL;// must initialize before using             

    example=foo(example);

    printf("%s\n",example);

    return 0;
}
char *foo(char* arr)
{
    arr="attempt";

    return arr;
}

【讨论】:

  • 我知道它可以使用 strcpy 函数。为什么使用 strcpy 函数不是未定义的行为?
  • @SeptemberSKY - 因为在这种情况下,参数example 已用内容初始化。在此之前,内容是未定义的,这意味着它可能不是一个 null 终止的字符数组,这是一个 C 字符串的定义。因此,strcpy() 可能有效,也可能无效。
  • 在第二种情况下,char *example = NULL; 就足够了。 “必须在使用前初始化,并且使用一个值......确保足够的空间”在这里不清楚。
【解决方案2】:

由于不同的原因,两者都不“工作”。

第一个是未定义的行为 (UB),因为代码尝试分配example[10] 范围之外的元素。

考虑到传递给foo() 的值,arr[0]='\0';arr[9]='\0'; 本来可以。

字符串文字 "attempt" 的地址转换为 char 也不是好的代码。启用良好的编译器会警告这种基本的编码失误。 @f3rmat example

char *foo(char arr[]) {
  arr[10]="attempt";  <-- UB
  return arr;
}

char example[10];
example=foo(example);

第二个是 UB,因为代码试图在传递指针时使用未初始化的值。这“有效”在于传递未初始化指针的 UB 通常是良性的。由于foo() 没有使用这个“垃圾”值,并且其余部分定义良好,因此它“有效”。

char *foo(char* arr) {
    arr="attempt";
    return arr;
}
char *example;
example=foo(example);   // UB - likely a garbage value is passed to `foo()`.
printf("%s\n",example); // `example` is now pointing to `"attempt"`. 

我学习 char 数组和 char 指针实际上是出于相同的目的。

指针和数组是相关的,但又不同。避免“实际用途相同”的想法。

数组就像街道上的一排房子。 指针是写在你手中的一张纸上的房子地址。房子≠废纸。你可以通过地址来指代房子,甚至可以通过第一所房子的地址来指代一排房子,但是房子和它的地址是不同的。

【讨论】:

  • 我的 gcc 版本是:gcc 版本 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.11) 并且代码 '2' 正在我的计算机上运行。
  • @SeptemberSKY 尝试编译更多警告,例如'-Wpedantic' '-Wall' '-Wextra' '-Wconversion'。 “代码‘2’正在我的电脑上运行。”并不意味着代码没有错误。具有未定义行为的代码可能似乎运行良好。
【解决方案3】:

字符数组可以初始化但不能赋值。 char example[10]="attempt"; 有效。

但是

char example[10];

example="attempt"

无效。

更多详情here

您的第二个示例有效,因为您将未初始化的指针传递给函数并返回字符串文字 attempt 的地址 正如chux的答案中提到的那样,这将完美地工作

【讨论】:

  • “字符数组可以初始化但不能赋值”是真的,但这里不清楚,因为 OP 的代码不会尝试在任何地方分配数组。
【解决方案4】:

指针和数组不一样。

char *arr = "attempt"

在这里,您正在创建一个字符串常量"attempt",并将其地址分配给arr,这是有效的

char arr[10];
arr = "attempt";

这是无效的。

您可以通过以下方法将元素添加到数组中。

char arr[10] = "attempt";
char arr[10] = {'a', 't', 't', 'e', 'm', 'p', 't'};
arr[0] = 'a';
arr[1] = 't'; // and so on.

当您将数组作为参数传递给另一个函数时

arr = foo(arr);

您正在传递数组 arr[0] 中第零个元素的地址

希望对您有所帮助..

【讨论】:

  • char arr[10] = "attempt"; 完全有效,无需将chars 一一分开。但是,这不是OP所做的。 OP 在foo 中有一个指针,而不是一个数组。
【解决方案5】:

我试图编译代码'1'并得到以下错误:

prog.c: In function ‘main’:
prog.c:8:12: error: assignment to expression with array type
example=foo(example);
prog.c: In function ‘foo’:
prog.c:14:12: warning: assignment makes integer from pointer without a cast [- 
Wint-conversion]
arr[10]="attempt\n";
        ^

您得到error: assignment to expression with array type example=foo(example);,因为在您的左侧,您使用的是不可分配的数组类型。赋值运算符 (=) 需要有一个可修改的左值作为其左操作数。

您会得到一个warning: assignment makes integer from pointer without a cast [Wint-conversion] arr[10]="attempt\n";,因为此作业的左侧和右侧具有不同的类型。

【讨论】:

  • 我解决了这个问题。
猜你喜欢
  • 2018-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-26
  • 2016-06-10
  • 1970-01-01
相关资源
最近更新 更多