Arduino resetting on loop?

Hey, I am doing a school project and my most recent version of code seems to be causing my Arduino Uno to reset every time it gets to the loop. It can only run through the setup, from what I have read this may be a memory issue but I am not too sure about it. I would love some help.

The purpose of the code is a model carpark security system, it uses LDRs to read the position of the car and an H bridge to control DC motors for the barrier arms. I have also included a 16x2 LCD display.

I apologize if my code is sloppy, I have tried my best to clean it up but I am insanely busy with school work

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x3f,20,4);  // set the LCD I2C address to 0x3f

//Setting the pins
const int LDR[] = {A0, A3, A1, A2}; //LDR pins
const int h[] = {9, 8, 7, 6};
const int buzzer = 13; 
const int button[] = {2, 3, 4, 5, 10};

int val[] = {};
int but[] = {};

int ArmUp[] = {0, 0}; //Arm position

int roomValA, roomValB; //Room light values
int ticket;
int cars, carsIn, emptySpaces; //Value for tracking cars and spaces
int spaces = 10; //Number of total spaces 

void setup() { //This code runs once when at the beginning of the code
  //Begining the serial monitor at 9600 baud
  Serial.begin(9600);
  Serial.println("Start");
  
  for(int n = 0; n <= 4; n++){
    pinMode(LDR[n], INPUT);
    pinMode(button[n], INPUT_PULLUP);
    pinMode(h[n], OUTPUT);
  }
  
  pinMode(buzzer, OUTPUT);//Declaring the buzzer as an output
  pinMode(button[4], INPUT_PULLUP);//Decalring the button as an input

  roomValA = ((analogRead(LDR[0])+ analogRead(LDR[1]))/200) - 1;  
  roomValB = ((analogRead(LDR[2]) + analogRead(LDR[3]))/200) - 1;  //Averaging all the LDRs to get the room value then prints the value
  sprintf("Room vals: %d /t %d", roomValA, roomValB); 

  lcd.init();// initialize the lcd 
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(1,0);
  lcd.print("Car park system V4");
  lcd.setCursor(1,1);
  lcd.print("Made by Robin Nowlan");
  delay(1000);
  lcd.clear(); //Sets up the LCD
}

void loop() { //Loops forever
  
//CODE RESETS AT THIS POINT

  //Reading all the inputs
  for(int i = 0; i <= 4; i++){
    Serial.println("read");
    val[i] = analogRead(LDR[i])/100;
    Serial.println(val[i]);
    but[i] = digitalRead(button[i]);
  }
  ticket = digitalRead(button[4]);
  
  if(but[0] == 0){
      LCDdisplay("Total cars:", cars);
    }
    if(but[1] == 0){
      LCDdisplay("Cars in:", carsIn);
    }
    if(but[2] == 0){
      LCDdisplay("Cars out:", cars - carsIn);
    }
    if(but[3] == 0){
      LCDdisplay("Time up:", millis()/1000);
    }
  
  emptySpaces = spaces - carsIn;

  Serial.print("Loop begin");
   //Main control loop
  //********************************************//
  if(val[0] < roomValA && ticket == LOW){
    if(ArmUp[0] == 0){
      for(int i = 0; i < 3; i++){
        digitalWrite(buzzer, HIGH);
        delay(500);
        digitalWrite(buzzer,LOW);
        delay(100);
      }
      digitalWrite(h[0], LOW);
      digitalWrite(h[1], HIGH);
      Serial.println("Entrance Arm Up");
      cars ++;
      carsIn ++;
      
      for(int z; z <= 5000; z++){     
       LCDdisplay("Time to go",z/1000);     
        delay(1);   
      }
      //delay(5000);
      digitalWrite(h[0], LOW);
      digitalWrite(h[1], LOW);
      Serial.println("Entrance Arm Stop");
      lcd.clear();
      lcd.setCursor((16/2)-2, 0);
      lcd.print("Go");
      lcd.setCursor((16/4)+(16/2), 0);
      lcd.print("|");
      lcd.setCursor((16/4)+(16/2), 1);
      lcd.print("V");
      lcd.setCursor((16/4), 1);
      lcd.print("X");
      delay(1000);
      lcd.clear();
      ArmUp[0] = 1;
    }
  }
  
  else if(val[0] >= roomValA && val[1] < roomValA){
    if(ArmUp[0] == 1){
      for(int i = 0; i < 3; i++){
        digitalWrite(buzzer, HIGH);
        delay(500);
        digitalWrite(buzzer,LOW);
        delay(100);
      }
      digitalWrite(h[0], HIGH);
      digitalWrite(h[1], LOW);
      Serial.println("Entrance Arm Down");
      delay(5000);
      digitalWrite(h[0], LOW);
      digitalWrite(h[1], LOW);
      Serial.println("Entrance Arm Stop");
      ArmUp[0] = 0;
    }
  }
  
  //Second arm
  if(val[3] < roomValB){
    if(ArmUp[1] == 0){
      for(int i = 0; i < 3; i++){
        digitalWrite(buzzer, HIGH);
        delay(500);
        digitalWrite(buzzer,LOW);
        delay(100);
      }
      digitalWrite(h[2], LOW);
      digitalWrite(h[3], HIGH);
      Serial.println("exit Arm up");
      carsIn --;
      
      for(int z; z <= 5000; z++){     
        LCDdisplay("Time to go",z/1000);     
        delay(1);   
      }
      //delay(4000);
      digitalWrite(h[2], LOW);
      digitalWrite(h[3], LOW);
      Serial.println("Exit Arm stop");  
      ArmUp[1] = 1;
    }
  }
  
  else if(val[3] >= roomValB && val[2] <= roomValB){
    if(ArmUp[1] == 1){
      for(int i = 0; i < 3; i++){
        digitalWrite(buzzer, HIGH);
        delay(500);
        digitalWrite(buzzer,LOW);
        delay(100);
      }
      digitalWrite(h[2], LOW);
      digitalWrite(h[2], HIGH);
      Serial.println("Exit Arm Down");  
      delay(4000);
      digitalWrite(h[2], LOW);
      digitalWrite(h[3], LOW);
      Serial.println("Exit Arm stop"); ;
      ArmUp[1] = 0;
    }
  }  
  //************************************************//
}

void  LCDdisplay(String x, int y){
  lcd.clear();
  lcd.print(x);
  lcd.setCursor(1,1);
  lcd.print(y);
}

The code compiles and uploads correctly but does not run, as well as this the serial monitor sometimes outputs gibberish rather than the expected outcome.

You are reading and writing off the ends of arrays.

Your test is n <=4 when looping over an array that has 4 elements. So when n=4 it will be reading the next byte in memory after the end of the array (who knows what that might be - and trivial/apparently-unrelated changes in the program can change how the variables are arranged in memory too).

And then you are writing to values in arrays of size 0. This is scribbling over whatever happens to be after the array in memory. Arrays are not dynamically sized - this is C, not javascript. Arrays are always of fixed size and the size must be set when they’re declared (or you go down the malloc rabbit hole and dynamically allocate memory - but this has a bunch of pitfalls on an embedded processor, and is almost always an inappropriate solution).
Writing off the end of an array almost always causes a reset - though it can definitely also cause all sorts of more complicated wacky behavior.

Is it ligit to have a declaration like:

int val[] = {};
int but[] = {};

and then assign variables to it in the loop?

I really do not know the answer to that, I am actually asking.

[Edit]: Answered by @DrAzzy while I typed. That is what I thought - just was not sure.

Willem

I see the problem now, I did not realise that the size of the array wasn't dynamic and had to be declared previously, also it was very stupid of me to try to write to the 5th item in a 4 item array in my for loops.

Thanks