مفهوم اعداد
در زبان C، اعداد به دو دستهٔ کلی تقسیم میشوند: اعداد صحیح (Integers) و اعداد اعشاری (Floating-Point Numbers). هر کدام از این دستهها، انواع دادههای مشخصی با اندازهها و محدودههای متفاوت دارند که انتخاب نوع مناسب، تأثیر مستقیم بر دقت، مصرف حافظه و کارایی برنامه دارد.
C یک زبان استاتیکتایپ است، بنابراین نوع عددی که در یک متغیر ذخیره میشود، در زمان کامپایل مشخص بوده و قابل تغییر نیست . انتخاب نوع دادهٔ صحیح به ماهیت داده (صحیح یا اعشاری)، محدودهٔ مورد نیاز و دقت لازم بستگی دارد.
۱. اعداد صحیح (Integers)
اعداد صحیح در C توسط انواع دادهای که با کلمهٔ کلیدی int یا مشتقات آن ساخته میشوند، نمایش داده میشوند. این نوعها برای ذخیرهٔ اعداد بدون جزء اعشاری (مانند تعداد، شمارنده، شناسه و شاخص) استفاده میشوند .
انواع پایهٔ اعداد صحیح
| نوع داده | اندازهٔ معمول | محدوده (با علامت/signed) | محدوده (بدون علامت/unsigned) | مشخصهٔ قالببندی |
|---|---|---|---|---|
char | ۱ بایت | ۱۲۷- تا ۱۲۷ | ۰ تا ۲۵۵ | %c یا %hhd |
short (یا short int) | ۲ بایت | ۳۲,۷۶۷- تا ۳۲,۷۶۷ | ۰ تا ۶۵,۵۳۵ | %hd |
int | ۴ بایت | ۲,۱۴۷,۴۸۳,۶۴۸- تا ۲,۱۴۷,۴۸۳,۶۴۷ | ۰ تا ۴,۲۹۴,۹۶۷,۲۹۵ | %d یا %i |
long (یا long int) | ۴ یا ۸ بایت | ۲,۱۴۷,۴۸۳,۶۴۷- تا ۲,۱۴۷,۴۸۳,۶۴۷ (حداقل) | ۰ تا ۴,۲۹۴,۹۶۷,۲۹۵ (حداقل) | %ld |
long long (یا long long int) | ۸ بایت | ۹.۲۲×۱۰¹⁸- تا ۹.۲۲×۱۰¹⁸ | ۰ تا ۱.۸۴×۱۰¹⁹ | %lld |
اندازهٔ دقیق این نوعها به کامپایلر و معماری سیستم بستگی دارد . بهعنوان مثال، int در بیشتر سیستمهای مدرن ۳۲ بیت (۴ بایت) است، اما در برخی سیستمهای قدیمی یا جاسازیشده ممکن است ۱۶ بیت (۲ بایت) باشد . استاندارد C فقط حداقل اندازهها را تضمین میکند .
علامتدار (signed) در مقابل بدونعلامت (unsigned)
بهطور پیشفرض، انواع اعداد صحیح علامتدار (signed) هستند؛ یعنی میتوانند اعداد مثبت و منفی را ذخیره کنند. با استفاده از اصلاحکنندهٔ unsigned، میتوان نوعی تعریف کرد که فقط اعداد مثبت و صفر را پشتیبانی میکند و در نتیجه، محدودهٔ مثبت آن دو برابر میشود :
int signed_num = -100; // ✅ اعداد منفی مجازند unsigned int unsigned_num = 40000; // ✅ فقط اعداد مثبت // unsigned int bad = -5; // ❌ مقدار منفی در unsigned قابل ذخیره نیست
نکته حرفهای: استفاده از
unsignedبرای مقادیری که هرگز منفی نیستند (مانند شناسهها، اندازهها و شمارندههای مثبت) میتواند با افزایش محدودهٔ مثبت، مفید باشد. با این حال، باید در محاسبات و مقایسهها باsignedدقت کرد، زیرا ترکیب این دو نوع ممکن است رفتار غیرمنتظرهای داشته باشد.
تعریف و مقداردهی اعداد صحیح
#include <stdio.h> int main() { // انواع پایه int count = 100; short small = 32000; long big = 1000000000L; // پسوند L برای long long long very_big = 10000000000LL; // پسوند LL برای long long unsigned int positive = 4000000000U; // پسوند U برای unsigned // چاپ با مشخصههای مناسب printf("int: %d\n", count); printf("short: %hd\n", small); printf("long: %ld\n", big); printf("long long: %lld\n", very_big); printf("unsigned int: %u\n", positive); return 0; }
نکته: پسوندهایی مانند
L,LL,Uبرای مشخص کردن نوع دقیق ثابتهای عددی استفاده میشوند. در بیشتر موارد، کامپایلر خودش نوع مناسب را انتخاب میکند، اما در شرایط خاص (مانند اعداد بسیار بزرگ)، این پسوندها ضروری هستند .
۲. اعداد اعشاری (Floating-Point Numbers)
اعداد اعشاری برای نمایش اعدادی که جزء اعشاری دارند (مانند دما، وزن، قیمت و مختصات) استفاده میشوند. این اعداد در حافظه بهصورت نمایش علمی دودویی (مانند ۰.۷۵ × ۲³) ذخیره میشوند .
انواع دادهٔ اعشاری
| نوع داده | اندازه | دقت (رقم اعشار معنیدار) | محدوده (تقریبی) | مشخصهٔ قالببندی |
|---|---|---|---|---|
float | ۴ بایت | ۶-۷ رقم | ±۳.۴×۱۰³⁸- | %f |
double | ۸ بایت | ۱۵-۱۶ رقم | ±۱.۷×۱۰³⁰⁸- | %lf |
long double | ۱۰-۱۶ بایت | ۱۸-۱۹ رقم (متغیر) | ±۱.۱×۱۰⁴⁹³²- | %Lf |
طبق مستندات GNU C، نوع double بهعنوان نوع عادی اعداد اعشاری در نظر گرفته میشود و در محاسبات علمی و عمومی، انتخاب اول است. نوع float بیشتر برای صرفهجویی در حافظه در آرایهها و ساختارهای بزرگ کاربرد دارد .
تعریف و مقداردهی اعداد اعشاری
#include <stdio.h> int main() { float temperature = 36.5f; // پسوند f برای float double pi = 3.14159265358979; // double پیشفرض است long double precise = 3.141592653589793238L; // پسوند L برای long double printf("float: %.2f\n", temperature); printf("double: %.15lf\n", pi); printf("long double: %.18Lf\n", precise); // نمایش علمی (scientific notation) double distance = 1.496e8; // 149,600,000 (فاصلهٔ زمین تا خورشید) double mass = 5.972e24; // جرم زمین (کیلوگرم) printf("Distance: %e km\n", distance); printf("Mass: %e kg\n", mass); return 0; }
نکته مهم: در
printf()، برای چاپfloatوdoubleاز%fاستفاده میشود (چونfloatبهطور خودکار بهdoubleارتقا مییابد). اما درscanf()، برایfloatباید از%fو برایdoubleاز%lfاستفاده کرد.
۳. انتخاب نوع عددی مناسب
انتخاب نوع دادهٔ صحیح تأثیر مستقیم بر کارایی، دقت و مصرف حافظه دارد:
| سناریو | نوع پیشنهادی | دلیل |
|---|---|---|
| شمارندهٔ حلقه، ایندکس آرایه | int | اندازهٔ استاندارد و کارآمد |
| شناسهٔ بزرگ (مثل ID مشتری) | long یا long long | پشتیبانی از محدودهٔ وسیع |
| مقادیر مثبت همیشه (مثل جمعیت) | unsigned int | افزایش محدودهٔ مثبت |
| دما، وزن، قیمت روزمره | float | دقت معمولی کافی است |
| محاسبات علمی، مختصات GPS، مالی دقیق | double | نیاز به دقت بالا |
| ذخیرهسازی مقادیر در آرایههای بزرگ | float | صرفهجویی در حافظه |
| محاسبات بسیار دقیق | long double | دقت فوقالعاده (در صورت نیاز) |
مثال: مقایسهٔ دقت float و double
#include <stdio.h> int main() { float f = 0.1f; double d = 0.1; float sum_f = 0.0f; double sum_d = 0.0; // جمع ۱۰ بار ۰.۱ for (int i = 0; i < 10; i++) { sum_f += f; sum_d += d; } printf("float sum of 0.1 * 10: %.20f\n", sum_f); // ممکن است 1.00000011920928955078 باشد printf("double sum of 0.1 * 10: %.20lf\n", sum_d); // معمولاً 1.00000000000000000000 return 0; }
این مثال نشان میدهد که float بهدلیل دقت کمتر، ممکن است در محاسبات تکراری، خطای گرد کردن بیشتری داشته باشد.
۴. تبدیل بین انواع عددی (Type Conversion)
C اجازهٔ تبدیل بین انواع عددی مختلف را میدهد. این تبدیل میتواند ضمنی (توسط کامپایلر) یا صریح (توسط برنامهنویس با Type Casting) باشد.
تبدیل ضمنی (Implicit Conversion)
زمانی که دو نوع متفاوت در یک عبارت شرکت میکنند، نوع کوچکتر به نوع بزرگتر ارتقا مییابد (تبدیل ارتقایی) تا دقت حفظ شود:
int a = 5; double b = 2.5; double result = a + b; // a بهصورت خودکار به double تبدیل میشود printf("%lf\n", result); // خروجی: 7.500000
اما در انتساب، اگر نوع بزرگتر به نوع کوچکتر نسبت داده شود، ممکن است دقت از دست برود یا سرریز اتفاق بیفتد:
double pi = 3.14159; float f = pi; // f = 3.14159 (دقت کمتری دارد) int i = pi; // i = 3 (بخش اعشاری حذف میشود)
تبدیل صریح (Explicit Casting)
برای کنترل دقیق تبدیل، از عملگر cast استفاده میشود:
int a = 10, b = 3; float result; result = (float)a / b; // تبدیل a به float قبل از تقسیم printf("%.2f\n", result); // خروجی: 3.33 (نه 3.00) // اگر cast نکنیم result = a / b; // تقسیم صحیح: 10/3 = 3 printf("%.2f\n", result); // خروجی: 3.00
۵. ثابتهای عددی (Numeric Constants)
اعداد ثابت در کد منبع، بر اساس قوانینی نوعدهی میشوند. نوع یک ثابت صحیح بهطور پیشفرض int است، مگر اینکه مقدار آن در int نگنجد که در آن صورت به ترتیب به long int و long long int ارتقا مییابد .
پسوندهای ثابتهای عددی
| پسوند | معنی | مثال |
|---|---|---|
U یا u | unsigned | 3000000000U |
L یا l | long | 100000L |
LL یا ll | long long | 10000000000LL |
UL یا ul | unsigned long | 4000000000UL |
F یا f | float | 3.14f |
L (برای اعشاری) | long double | 3.14159L |
// ثابتهای صحیح با پسوند long big = 1000000000L; unsigned long bigger = 4000000000UL; long long very_big = 9000000000000000000LL; // ثابتهای اعشاری با پسوند float pi_float = 3.14159f; long double pi_long = 3.141592653589793238L;
توجه: برای ثابتهای اعشاری،
doubleنوع پیشفرض است. برای ساختfloatیاlong doubleباید از پسوند استفاده کرد.
۶. مثالهای عملی
مثال ۱: محاسبهٔ میانگین نمرات
#include <stdio.h> int main() { // استفاده از int برای نمرات و تعداد int scores[] = {85, 90, 78, 92, 88}; int count = 5; int sum = 0; for (int i = 0; i < count; i++) { sum += scores[i]; } // برای دقت بیشتر، از double برای میانگین استفاده میکنیم double average = (double)sum / count; // cast صریح برای تقسیم اعشاری printf("Sum: %d\n", sum); printf("Count: %d\n", count); printf("Average: %.2f\n", average); return 0; }
مثال ۲: محاسبهٔ مساحت دایره با دقت بالا
#include <stdio.h> int main() { const double PI = 3.141592653589793; // double برای دقت بالا double radius; printf("Enter radius: "); scanf("%lf", &radius); // %lf برای double در scanf double area = PI * radius * radius; double circumference = 2 * PI * radius; printf("Area: %.10lf\n", area); printf("Circumference: %.10lf\n", circumference); // نمایش اندازهٔ حافظه printf("Size of double: %zu bytes\n", sizeof(double)); return 0; }
مثال ۳: مدیریت موجودی انبار
#include <stdio.h> int main() { // استفاده از unsigned برای مقادیر مثبت unsigned int stock = 150; unsigned int sold = 35; unsigned int restock = 50; // محاسبهٔ موجودی جدید (مقادیر منفی نیستند) unsigned int new_stock = stock - sold + restock; // محاسبهٔ قیمت کل با استفاده از double برای دقت مالی double price_per_unit = 45.99; double total_value = (double)new_stock * price_per_unit; printf("Current stock: %u items\n", new_stock); printf("Total value: $%.2f\n", total_value); return 0; }
خطاهای رایج
۱. سرریز (Overflow) در انواع کوچک
unsigned char small = 255; small = small + 1; // ❌ سرریز: small = 0 (بازگشت به صفر)
راهحل: از نوع بزرگتر (unsigned short یا int) استفاده کنید.
۲. از دست رفتن دقت در تقسیم
int a = 5, b = 2; float result = a / b; // ❌ result = 2.0 (نه 2.5)
راهحل: حداقل یکی از عملوندها را به float یا double cast کنید.
۳. مقایسهٔ float با ==
float f = 0.1f; if (f == 0.1) { // ❌ ممکن است false شود // ... }
راهحل: از مقایسه با یک آستانهٔ خطا (epsilon) استفاده کنید: if (fabs(f - 0.1) < 0.00001).
۴. استفاده از %d برای long long
long long big = 10000000000LL; printf("%d", big); // ❌ رفتار نامشخص (چون %d برای int است)
راهحل: از مشخصهٔ مناسب استفاده کنید: %lld.
۵. مخلوط کردن signed و unsigned
int signed_val = -1; unsigned int unsigned_val = 10; if (signed_val < unsigned_val) { // ⚠️ ممکن است false شود // این کد ممکن است اجرا نشود }
راهحل: از تبدیل صریح استفاده کنید یا از مقایسه با int خودداری کنید.
۶. فراموش کردن پسوند برای اعداد بزرگ
long big = 10000000000; // ⚠️ ممکن است warning دهد (عدد در int نمیگنجد) long big = 10000000000L; // ✅ صحیح
خلاصه و نکات کلیدی
-
اعداد صحیح با انواع
int,short,long,long longو نسخهٔunsignedآنها ذخیره میشوند -
اعداد اعشاری با انواع
float,doubleوlong doubleذخیره میشوند -
اندازهٔ دقیق انواع به کامپایلر و سیستمعامل بستگی دارد؛ از
sizeofبرای بررسی استفاده کنید -
نوع
doubleبرای محاسبات علمی و دقیق، وfloatبرای صرفهجویی در حافظه مناسب است -
از
unsignedبرای مقادیری که هرگز منفی نیستند استفاده کنید -
در تقسیم اعداد صحیح، برای حفظ دقت، حداقل یکی از عملوندها را cast کنید
-
از مشخصهٔ قالببندی مناسب (
%d,%ld,%lld,%f,%lf,%Lf) استفاده کنید -
اعداد اعشاری را با
==مقایسه نکنید؛ از یک آستانهٔ خطا استفاده کنید -
در صورت نیاز به دقت بالا در محاسبات مالی و علمی،
doubleانتخاب بهتری است
این محتوا کاملا رایگان توسط تیم کدلپر ترجمه شده و در اختیار شما کاربران عزیز قرار گرفته است، هر گونه کپی برداری برای مقاصد غیر رایگان و بدون ذکر منبع، مورد پیگیری قانونی قرار میگیرد.
ترجمه شده از منبع: منبع مستندات