Trả về mà không có lệnh quay trở lại


8

Ngôn ngữ lập trình C, được biên dịch bằng gcc, bash terminal trong WSL

Tôi đã viết một hàm đệ quy, để tìm số thấp nhất trong một mảng, hoạt động tốt.

/*01*/    int minimo(int array[], int n)
/*02*/    {
/*03*/      static int min = 0;
/*04*/    
/*05*/      if (n == N)
/*06*/      {
/*07*/          return array[n-1];
/*08*/      }
/*09*/      else
/*10*/      {
/*11*/          min = minimo(array, n+1);
/*12*/          if(array[n]<min){
/*13*/              min = array[n];
/*14*/          }
/*15*/      }
/*16*/    }

Vấn đề duy nhất là nó không hoạt động, vì nó không trả lại "min" cho người gọi ...

int main()
{
    //Var
    int array[N] = {10, 2, 5, 1, 7};
    printf("Min: %d\n", minimo(array, 0));
}

Mối quan tâm của tôi thực sự là một vấn đề, nhưng không phải trên máy của tôi mà chức năng hoạt động tốt như nó vốn có; đó là một vấn đề trên máy tính xách tay và IDE của bạn bè tôi, tôi đã thử sao chép vào XCode trên Macbook của một người bạn và nó sẽ không hoạt động nếu dòng "return min;" không được thêm vào cuối chức năng.

Giữa dòng 15-16 tôi phải thêm return min;

/*15*/      }
            return min;
/*16*/    }

Câu hỏi của tôi cho bạn là như sau:

  1. Làm thế nào một hàm có thể trả về một biến tự động ?
  2. Có thể là nó trả về biến duy nhất mà tôi đã tạo (static int min) không?
  3. Hay đó là một "vấn đề" liên quan đến thuộc tính tĩnh mà biến có?
  4. Nó có liên quan gì đến bản chất của hàm ( đệ quy ) không?

Đây là bài viết đầu tiên của tôi, xin vui lòng tử tế nếu tôi vi phạm bất kỳ quy tắc diễn đàn nào.


Đọc qua câu hỏi SO: stackoverflow.com/q/204476/8339821 và các câu trả lời. Điều này sẽ đưa bạn đến điểm mà mainchức năng của bạn trở lại.
yvw

Ngay từ cái nhìn đầu tiên, nó có vẻ như là một thứ cụ thể của WSL, không dành riêng cho gcc. Dường như WSL tự động "nghĩ" cho bạn và tự sửa mã.
RobertS hỗ trợ Monica Cellio

@ Рос mặc dù đây là một điều hoàn toàn khác và không liên quan gì đến câu hỏi này. Vấn đề không phải là về giá trị trả về của mainnó là về giá trị trả về "tự động" của một hàm trong một triển khai cụ thể.
RobertS hỗ trợ Monica Cellio

@RobertSsupportsMonicaCellio Vâng, bạn đã đúng. Tôi đọc lại câu hỏi một lần nữa và tôi nhận được rằng SO muốn biết chức năng của anh ta thực sự trở lại là gì. Tôi nghĩ rằng bằng cách nào đó anh ấy bỏ lỡ sự trở lại từ chính. Sau đó, câu trả lời này cung cấp thông tin đầy đủ về chủ đề: stackoverflow.com/a/1610454/8339821 . Điểm chính là ở chỗ, một số Ctiêu chuẩn cụ thể trả về 0 trong sự vắng mặt của một tuyên bố trả lại.
yvw

Bạn nên biên dịch tệp của mình bằng một -Wallcông tắc và xem trình biên dịch cho bạn biết điều gì.
yvw

Câu trả lời:


5

Mối quan tâm của tôi thực sự là một vấn đề, nhưng không phải trên máy của tôi mà chức năng hoạt động tốt như nó vốn có; đó là một vấn đề trên máy tính xách tay và IDE của bạn bè tôi, tôi đã thử sao chép vào XCode trên Macbook của một người bạn và nó sẽ không hoạt động nếu dòng "return min;" không được thêm vào cuối chức năng.

Ví dụ điển hình của hành vi không xác định . Hoạt động trên một máy nhưng không phải máy khác. Hoạt động vào ban ngày nhưng không phải ban đêm. Hoạt động với một trình biên dịch nhưng không phải là trình biên dịch khác. Khi bạn gọi hành vi không xác định, tiêu chuẩn C áp đặt không có yêu cầu nào về cách hành xử của mã.

Tiêu chuẩn C11 6.9.1.12

Nếu} kết thúc một hàm được đạt tới và giá trị của lệnh gọi hàm được người gọi sử dụng, hành vi không được xác định.

Trong mã của bạn, đó chính xác là những gì xảy ra. Bạn gọi hành vi không xác định khi bạn cố in giá trị trả về.

Trái với những gì nhiều người tin, nó hoàn toàn được phép bỏ qua câu lệnh return trong hàm không trống. Nó chỉ trở thành hành vi không xác định nếu bạn cố gắng sử dụng giá trị trả về không tồn tại.

Để tránh điều này, luôn luôn biên dịch với ít nhất -Wall -Wextra.


Và đừng quên -Werror!
Jonathon Reinhart

@JonathonReinhart Vâng, đó là loại thảo luận cần bia. :)
klutt

1
@JonathonReinhart Điều quan trọng là thực sự quan tâm đến các cảnh báo. Nếu lập trình viên không quan tâm và đang sử dụng -WerrorSO sẽ nhận được một câu hỏi với "Tại sao điều này không được biên dịch?" và không có nó "Tại sao điều này hành xử kỳ lạ?" Mặc dù tôi đồng ý rằng tham số đó là một điều tốt, nhưng nó lại bỏ lỡ mục tiêu.
klutt

1
Cảm giác của tôi là -Werrorngăn chặn những câu hỏi SO không cần thiết như câu hỏi này, bởi vì người dùng buộc phải quan tâm đến các cảnh báo khi họ không có khả năng thực thi bị hỏng để chạy :-)
Jonathon Reinhart

2
Theo mặc định, có lẽ GCC chỉ nên trình bày các thông báo lỗi ở định dạng HTML với chủ đề Stack Overflow và kết quả tìm kiếm được nhúng
Jonathon Reinhart

2

Làm thế nào một hàm có thể trả về một biến tự động?

Nó tuân theo giao thức. Nó biết rằng sự trở lại của hàm sẽ tìm giá trị được trả về tại một vị trí nào đó và một hàm rõ ràng returntừ hàm đó sẽ điền vào vị trí đó. Nếu bạn không gọi return, một số giá trị ngẫu nhiên sẽ được giữ nguyên tại vị trí đã cho.

Có thể là nó trả về biến duy nhất mà tôi đã tạo (static int min) không?

Không, nó không xác định những gì nó trả lại. Nó có thể là bất cứ điều gì.

Hay đó là một "vấn đề" liên quan đến thuộc tính tĩnh mà biến có?

Một lần nữa, những gì nó trả lại là không xác định.

Nó có liên quan gì đến bản chất của hàm (đệ quy) không?

Có và không. Nếu hàm được định nghĩa là bên ngoài, giá trị trả về sẽ theo một giao thức khác như trong trường hợp hàm tĩnh.

Nó có thể xảy ra bất cứ điều gì trong mã cuối cùng, ngôn ngữ C không áp đặt cách thực hiện một chức năng, có thể đệ quy hay không. Ví dụ, trong trường hợp hàm đệ quy và có thể được tính toán trước, chỉ có thể thay thế giá trị cuối cùng tại nơi gọi. Điều này cũng đúng theo thời gian vì kết quả cuối cùng của chương trình là kết quả mong đợi, phù hợp với ngữ nghĩa hoạt động xác định C trong ISO9899.

Tôi trích dẫn từ tài liệu chính thức:

4 Trong máy trừu tượng, tất cả các biểu thức được đánh giá theo quy định của ngữ nghĩa. Việc triển khai thực tế không cần đánh giá một phần của biểu thức nếu nó có thể suy ra rằng giá trị của nó không được sử dụng và không có tác dụng phụ cần thiết nào được tạo ra (bao gồm mọi tác nhân gây ra bằng cách gọi hàm hoặc truy cập một đối tượng dễ bay hơi).

Nó cũng có thể thay thế một cuộc gọi bằng giá trị của cuộc gọi đó và điều này là chính xác.

Vì vậy, tại tất cả các câu hỏi của bạn, câu trả lời là hành vi không xác định .


1

Làm thế nào một hàm có thể trả về một biến tự động?

Tôi tình cờ, minbiến xảy ra trong sổ đăng ký hoàn trả chính xác cho ABI.

Có thể là nó trả về biến duy nhất mà tôi đã tạo (static int min) không?

Tôi nghĩ rằng nó liên quan nhiều hơn đến việc nó đã được sử dụng ngay trước khi thoát chức năng, nhưng tôi đoán ở đây: đây không phải là hành vi được xác định bằng ngôn ngữ C và nó hoạt động tình cờ.

Hay đó là một "vấn đề" liên quan đến thuộc tính tĩnh mà biến có?

Nó có liên quan gì đến bản chất của hàm (đệ quy) không?

Vì đây là một hành vi cơ hội, có thể hoặc không. Sự khác biệt giữa ngẫu nhiên và xác định là bạn có quá nhiều biến số mà bạn từ bỏ giải thích.


-3

Tôi cho rằng bạn đã xác định N ở đâu đó (có thể là N = 5 trong trường hợp của bạn).

Hầu hết các trình biên dịch tự động thêm câu lệnh "return 0" nếu câu lệnh return bị thiếu.

* Xem bình luận để biết thêm. Trên thực tế, đó là một hành vi không xác định *

Trong hàm đệ quy của bạn, tốt hơn là vượt qua độ dài còn lại của mảng và dừng khi bạn đạt n == 0.

Tránh nhìn vào các biến toàn cục hoặc định nghĩa các hàm bên trong.

int minimo(int array[], int n)
{
  ...
  if (n == 0)
  ...
            min = minimo(array, n-1);
  ...
}

(yêu cầu sửa đổi khác)

Trên thực tế bạn chỉ nên biết độ dài của mảng trên hàm chính, vì vậy hãy gọi nó là:

printf("Min: %d\n", minimo(array, N));

5
Không! Ngoại trừ main()trong các triển khai C99 (hoặc mới hơn) (trong đó a return 0;được thêm vào trong trường hợp không có tuyên bố hoàn trả trước đó) , không thành công returnlà UB .
pmg

@pmg ở đâu đó trên SO tôi đã đọc từ đó đi xuống C89. Và đó là mức tối thiểu tôi có thể có được ngày hôm nay.
yvw

@ Рос mặc dù là: C89 không đề cập đến giá trị trả về mặc định; C99 (và tương tự trong C11 ): "... đạt đến} kết thúc hàm chính trả về giá trị 0." (nhấn mạnh là của tôi)
pmg
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.