Противоречивая точка между массивом char и указателем char с возвратом адреса - PullRequest
0 голосов
/ 16 февраля 2019

Моя основная цель состояла в том, чтобы создать строку в некотором виде, она должна возвращать адрес, возвращая адрес, используя строку в main.Но я узнал, что массив char и указатель char фактически используют одну и ту же цель.

Если мы предположим, что у нас есть это замедление,

char *arr и char arr[10], *(arr+9)=arr[10] не так ли?

Код «1» не работает.

Код «2» работает.
Почему?

Код «1»:

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

int main(){

    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()
{
 char *example;

    example=foo(example);

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

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

    return arr;
}

Ответы [ 5 ]

0 голосов
/ 16 февраля 2019

Символьные массивы могут быть инициализированы, но не могут быть назначены.char example[10]="attempt"; действителен.

Но

char example[10];

example="attempt"

недействителен.

Подробнее здесь

Ваш второй пример работает, потому что вы передаете неинициализированный указатель на функцию и возвращаете адрес строкового литерала attempt, который будет прекрасно работать, как указано в ответе chux

0 голосов
/ 16 февраля 2019

Ваш код будет вызывать неопределенное поведение в обоих сегментах.(Даже если вы заметили, что код 2 работает , он работает только . На самом деле, сбой скрывается ,и может отображаться без предупреждения.)

Внесите эти исправления для решения этой проблемы и просмотрите комментарии для объяснений:

В код 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;
}

Чтобы ответить на ваш вопрос в комментариях: Зачем использовать функцию strcpy [ после переменной пример было инициализировано ] не является неопределенным поведением .
Во-первых, важно знать определение строки C.( Определение строки C находится здесь .)
Переменная 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 - инициализация указателя перед использованием: (См.причина, по которой указатель должен быть инициализирован здесь .)

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;
}
0 голосов
/ 16 февраля 2019

Указатель и массив не совпадают.

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]

Надеюсь, что поможет ..

0 голосов
/ 16 февраля 2019

Оба не «работают» по разным причинам.

Первое - неопределенное поведение (UB), поскольку код пытается назначить элемент за пределами example[10].

arr[0]='\0'; или arr[9]='\0'; были бы в порядке, если бы значение передавалось foo().

Преобразование адреса строкового литерала "attempt" вchar тоже не хороший код.Хорошо включенный компилятор предупредит об этом простом коде. @ f3rmat пример

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 фактически используяодна и та же цель.

Указатели и массивы связаны, но различны.Избегайте идеи «фактически использовать одну и ту же цель».

Массив подобен ряду домов на улице. указатель - это адрес дома, написанный на листке бумаги в вашей руке.Дома ≠ клочок бумаги.Вы можете ссылаться на дом по его адресу или даже по ряду домов по адресу первого дома, но дом и его адрес разные.

0 голосов
/ 16 февраля 2019

Я попытался скомпилировать код '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);, потому что в левой части вы используете тип массива, который нельзя назначить,Оператор присваивания (=) должен иметь изменяемое lvalue в качестве своего левого операнда.

Вы получаете warning: assignment makes integer from pointer without a cast [Wint-conversion] arr[10]="attempt\n";, потому что левая и правая части в этом назначении имеют разные типы.

...