2010-01-15 4 views
19

Đến từ một nền Java Tôi đang học C, nhưng tôi thấy những thông báo lỗi biên dịch mơ hồ ngày càng bực bội. Đây là mã của tôi:Bài tập làm cho con trỏ từ số nguyên mà không cần cast

/* 
* PURPOSE 
*  Do case-insensetive string comparison. 
*/ 
#include <stdio.h> 
#include <string.h> 
#include <ctype.h> 

int compareString(char cString1[], char cString2[]); 
char strToLower(char cString[]); 

int main() { 
    // Declarations 
    char cString1[50], cString2[50]; 
    int isEqual; 

    // Input 
    puts("Enter string 1: "); 
    gets(cString1); 
    puts("Enter string 2: "); 
    gets(cString2); 

    // Call 
    isEqual = compareString(cString1, cString2); 
    if (isEqual == 0) 
     printf("Equal!\n"); 
    else 
     printf("Not equal!\n"); 

    return 0; 
} 

// WATCH OUT 
//  This method *will* modify its input arrays. 
int compareString(char cString1[], char cString2[]) { 
    // To lowercase 
    cString1 = strToLower(cString1); 
    cString2 = strToLower(cString2); 

    // Do regular strcmp 
    return strcmp(cString1, cString2); 
} 

// WATCH OUT 
//  This method *will* modify its input arrays. 
char strToLower(char cString[]) { 
    // Declarations 
    int iTeller; 

    for (iTeller = 0; cString[iTeller] != '\0'; iTeller++) 
     cString[iTeller] = (char)tolower(cString[iTeller]); 

    return cString; 
} 

Điều này tạo ra hai cảnh báo.

  • phân công làm cho con trỏ từ số nguyên mà không có một dàn diễn viên
    • cString1 = strtolower (cString1);
    • cString2 = strToLower (cString2);
  • trở lại làm cho số nguyên từ con trỏ mà không có một dàn diễn viên
    • trở CString;

Ai đó có thể giải thích những cảnh báo này?

Trả lời

36

Chuỗi C không giống bất kỳ chuỗi Java nào. Chúng chủ yếu là mảng ký tự.

Bạn đang gặp lỗi vì strToLower trả về một char. Một char là một dạng của số nguyên trong C. Bạn đang gán nó vào một char [] mà là một con trỏ. Do đó "chuyển đổi số nguyên thành con trỏ".

strToLower của bạn thực hiện tất cả các thay đổi của nó tại chỗ, không có lý do gì để nó trả về bất cứ điều gì, đặc biệt không phải là một char. Bạn nên "trả về" void, hoặc một char *.

Khi gọi hàm strToLower, cũng không cần gán, bạn về cơ bản chỉ cần chuyển địa chỉ bộ nhớ cho cString1. Theo kinh nghiệm của tôi, Strings in C là phần khó nhất để học cho bất kỳ ai đến từ nền Java/C# trở lại C. Mọi người có thể cùng với việc cấp phát bộ nhớ (kể cả trong Java bạn thường phân bổ mảng). Nếu mục tiêu cuối cùng của bạn là C++ và không phải C, bạn có thể muốn tập trung ít hơn vào chuỗi C, hãy đảm bảo bạn hiểu những điều cơ bản và chỉ sử dụng chuỗi C++ từ STL.

+0

(+1) điều này cho biết thêm giá trị tự động trả lời –

+0

Điều này không ** trực tiếp ** giải quyết chủ đề của câu hỏi của bạn - một giải pháp gián tiếp: D để loại bỏ câu trả lời tự động của trình biên dịch là apt: D –

+0

Ok, làm rõ câu trả lời ở đây. – Uri

4

strtolower của kiểu trả về nên char* không char (hoặc nó phải trả lại gì cả, vì nó không tái bố trí chuỗi)

+0

(+1, gần -1 = D) Điều bạn muốn nói là thay đổi kiểu trả về ..... nó trả về char *, tuy nhiên điều này mâu thuẫn với kiểu trả về ... –

+0

Đã sửa lỗi. Cảm ơn tôi đã không rõ ràng về điều đó :) – James

1
  • 1) Không sử dụng gets! Bạn đang giới thiệu một lỗ hổng tràn bộ đệm. Sử dụng fgets(..., stdin) để thay thế.

  • 2) Trong strToLower bạn đang trả lại char thay vì char -array. Hoặc trả lại char* là Được đề xuất tự động hoặc chỉ trả lại void vì bạn vẫn đang sửa đổi đầu vào.Kết quả là, chỉ cần viết

 

strToLower(cString1); 
strToLower(cString2); 
  • 3) Để so sánh case-insensitive chuỗi, bạn có thể sử dụng strcasecmp (Linux & Mac) hoặc stricmp (Windows).
0

Bạn không cần hai assigments này:

cString1 = strToLower(cString1); 
cString2 = strToLower(cString2); 

bạn đang sửa đổi các dây tại chỗ.

Warnings là bởi vì bạn đang trả lại một char, và gán cho một char [] (tương đương với char *)

-1
char cString1[] 

Đây là một mảng, tức là một con trỏ đến phần tử đầu tiên của một loạt các phần tử của cùng một kiểu dữ liệu. Lưu ý rằng bạn không chuyển mảng theo giá trị mà bằng con trỏ.

char strToLower(...) 

Tuy nhiên, điều này trả về một char. Vì vậy, nhiệm vụ của bạn

cString1 = strToLower(cString1); 

có các loại khác nhau trên mỗi bên của toán tử gán .. bạn đang thực sự gán một 'char' (loại số nguyên) đến một mảng, mà giải quyết cho một con trỏ đơn giản. Do quy tắc chuyển đổi ngầm của C++ hoạt động, nhưng kết quả rác và tiếp tục truy cập vào mảng gây ra hành vi không xác định.

Giải pháp là thực hiện strToLower trả lại char*.

0

Bạn đang trả về char chứ không phải char *, là con trỏ trỏ đến ký tự đầu tiên của mảng.

Nếu bạn muốn trả về mảng ký tự mới thay vì thực hiện sửa đổi tại chỗ, bạn có thể yêu cầu con trỏ đã được phân bổ (char *) làm tham số hoặc con trỏ chưa được khởi tạo. Trong trường hợp cuối cùng này, bạn phải phân bổ số ký tự thích hợp cho chuỗi mới và nhớ rằng trong các tham số C được truyền bởi giá trị ALWAYS, vì vậy bạn phải sử dụng tham số char ** làm trường hợp mảng được phân bổ nội bộ theo hàm. Tất nhiên, người gọi phải giải phóng con trỏ đó sau.

0

strToLower phải trả về một char * thay vì một char. Một cái gì đó như thế này sẽ làm.

char *strToLower(char *cString) 
2

Như những người khác đã lưu ý, trong một trường hợp bạn đang cố gắng để trở cString (đó là một giá trị char * trong bối cảnh này - một con trỏ) từ một hàm được khai báo để trả lại một char (đó là một số nguyên) . Trong trường hợp khác bạn làm ngược lại: bạn đang gán giá trị trả về char cho con trỏ char *. Đây là những gì kích hoạt cảnh báo. Bạn chắc chắn cần khai báo các giá trị trả lại của mình là char *, không phải là char.

Lưu ý BTW rằng các bài tập này thực tế là vi phạm ràng buộc từ quan điểm ngôn ngữ (tức làchúng là "lỗi"), vì việc kết hợp các con trỏ và các số nguyên trong C giống nhau là bất hợp pháp (trừ một hằng số không đổi). Trình biên dịch của bạn chỉ đơn giản là quá tha thứ về vấn đề này và báo cáo những vi phạm này chỉ là "cảnh báo".

Điều tôi cũng muốn lưu ý là trong một số câu trả lời bạn có thể nhận thấy đề xuất tương đối lạ để trả về void từ các chức năng của bạn, vì bạn đang sửa đổi chuỗi tại chỗ. Trong khi nó chắc chắn sẽ làm việc (vì bạn thực sự đang sửa đổi chuỗi tại chỗ), không có gì thực sự sai khi trả về cùng một giá trị từ hàm. Trong thực tế, nó là một thực hành khá chuẩn trong ngôn ngữ C nếu có (hãy xem các hàm chuẩn như strcpy và các hàm khác), vì nó cho phép "chuỗi" các cuộc gọi hàm nếu bạn chọn sử dụng nó, và chi phí hầu như không có gì nếu bạn không sử dụng "chuỗi".

Điều đó nói rằng, các bài tập trong việc bạn triển khai compareString trông hoàn toàn không cần thiết cho tôi (mặc dù chúng sẽ không làm hỏng bất kỳ thứ gì). Tôi muốn một trong hai để loại bỏ chúng

int compareString(char cString1[], char cString2[]) { 
    // To lowercase 
    strToLower(cString1); 
    strToLower(cString2); 

    // Do regular strcmp 
    return strcmp(cString1, cString2); 
} 

hoặc sử dụng "chain" và làm

int compareString(char cString1[], char cString2[]) { 
    return strcmp(strToLower(cString1), strToLower(cString2)); 
} 

(đây là khi char * trở lại của bạn sẽ đến tiện dụng). Chỉ cần nhớ rằng các cuộc gọi hàm "chuỗi" đôi khi rất khó gỡ lỗi với trình gỡ lỗi từng bước.

Là một lưu ý bổ sung, không thực hiện, tôi muốn nói rằng thực hiện hàm so sánh chuỗi theo kiểu phá hoại như vậy (nó sửa đổi chuỗi đầu vào) có thể không phải là ý tưởng hay nhất. Một chức năng không phá hủy sẽ có giá trị lớn hơn nhiều trong quan điểm của tôi. Thay vì thực hiện chuyển đổi rõ ràng các chuỗi đầu vào thành chữ thường, tốt hơn là nên triển khai hàm so sánh chuỗi không phân biệt chữ hoa chữ thường và sử dụng nó thay vì gọi tiêu chuẩn strcmp.