Почему printf изменяет предыдущие локальные переменные?

Я попытался понять поведение C и обнаружил несколько странных вещей. Я отладил и обнаружил, что значения таблицы верны до вызова printf. Я создаю функцию void, чтобы проверить, является ли это проблемой области действия, но после вызова этой функции значения таблицы по-прежнему оставались правильными. Теперь мне интересно, удалит ли printf предыдущие локальные переменные.

#include <stdio.h>
#include <stdlib.h>
void invertTable(int** tableau,int size){
    int temp[size];
    for(int i = 0; i < size; i++)
    {
        temp[i]=-1*tableau[0][i];
    }
    tableau[0]=temp;
}
void test(){

}
int main(int argc, char const *argv[])
{
    int* table=(int*)malloc(5*sizeof(int));
    table[0]=1;
    table[1]=2;
    table[2]=3;
    table[3]=4;
    table[4]=5;
    invertTable(&table,5);
    test();
    for(int i = 0; i < 5; i++)
    {
        //Here is the problem
        printf("\n %d \n",table[i]);
    }
    free(table);
    return 0;
}

Ожидается -1 -2 -3 -4 -5

Выход: -1 1962295758 1 1962550824 1962295741

Когда вы назначаете tableau[0] = temp; переменная temp является локальной, поэтому она освобождается после возврата из функции. Итак, ваша таблица указывает на нераспределенную память. Тогда поведение не определено, вызов printf, вероятно, перераспределяет часть памяти там, где была temp, поэтому вы видите мусор...

user1531591 08.04.2019 11:22

См. geeksforgeeks.org/return-local-array-c-function

Déjà vu 08.04.2019 11:23
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
127
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Чтобы иметь правильный вывод, вы должны изменить

int temp[size] в int* temp = *tableau или в int* temp = (int*) malloc(sizeof(**tableau) * size).

Эти решения работают, потому что *tableau и/или память, выделенная malloc, не уничтожается после invertTable.

Обычно temp должен быть уничтожен после invertTable функции и создания tableau[0]оборванный указатель, тогда система может перераспределить память, на которую указывает temp. Таким образом, эта часть памяти теперь может содержать случайные данные. Эти данные, вероятно, то, что вы получили во время выполнения.

Ваша проблема не связана с printf, это связано с ошибкой в ​​​​вашем коде, когда вы пытаетесь использовать память, которую не должны использовать.

В этой строке в вашей функции invertTable:

 tableau[0]=temp;

Вы указываете указатель table в функции main() на локальную переменную temp.

Ваш массив temp выходит за пределы области видимости, когда функция invertTable завершается, поэтому вы получаете висячий указатель, и вы больше не можете использовать эту память - это поведение undefined.

Вместо этого вы можете динамически выделять память, которая останется в силе после окончания invertTable:

int *temp = malloc(sizeof(int) * size);
for(int i = 0; i < size; i++)
{
    temp[i]=-1*tableau[0][i];
}
//deallocate previous allocation
free(tableau[0]);
tableau[0]=temp;

Ваша проблема не связана с printf, она действительно invertTable виновата.

При работе с массивами table равно &table[0], поэтому в этом случае вам не нужно отправлять адрес таблицы.

#include <stdio.h>
#include <stdlib.h>
void invertTable(int *tableau,int size){
  for(int i = 0; i < size; i++)
    {
      tableau[i] = -1 * tableau[i];
    }
}
void test(){

}
int main(int argc, char const *argv[])
{
  int* table = (int*) malloc(5 * sizeof(int));
  table[0]=1;
  table[1]=2;
  table[2]=3;
  table[3]=4;
  table[4]=5;
  invertTable(table,5);
  test();
  for(int i = 0; i < 5; i++)
    {
      //Here is the problem
      printf("\n %d \n",table[i]);
    }
  free(table);
  return 0;
}

это сделает то, что вы ищете. Кроме того, вам также не нужно использовать какую-либо временную переменную.

Кстати, temp был временным, он не был выделен в куче, поэтому он был уничтожен, когда invertTable вернулся.

tableau[0]=temp;

Это недействительно. Это означает вернуть указатель на локальный массив. Это неопределенное поведение.

Вы можете сделать так:

for(int i = 0; i < size; i++)
    (*tableau)[i]*=-1;

Другие вопросы по теме