زبان C دو تا عملگر خاص برای زیاد کردن یا کم کردن مقدار متغیرها داره. عملگر ++ یه واحد به متغیرش اضافه میکنه، و عملگر -- یه واحد ازش کم میکنه.
ما تا حالا چند بار از ++ استفاده کردیم، مثلاً:
if (c == '\n')
++nl;
نکتهی جالب اینه که ++ و -- میتونن بهصورت پیشوند (قبل از متغیر مثل ++n) یا پسوند (بعد از متغیر مثل n++) استفاده بشن. توی هر دو حالت، متغیر n یکی زیاد میشه،
ولی فرقشون توی ترتیب انجام کاره:
-
++n یعنی اول n زیاد میشه، بعد مقدارش استفاده میشه.
-
n++ یعنی اول مقدار فعلی استفاده میشه، بعد n زیاد میشه.
مثلاً اگه n برابر ۵ باشه:
x = n++;
باعث میشه x برابر ۵ بشه، ولی
x = ++n;
باعث میشه x برابر ۶ بشه.
در هر دو حالت در آخر n برابر ۶ میشه.
نکتهی مهم اینه که ++ و -- فقط روی متغیرها قابل استفادهان. مثلاً (i + j)++ غیرقانونیه.
اگه جایی فقط خودِ عمل افزایش مهم باشه و مقدار نهایی استفاده نشه، مثل:
if (c == '\n')
nl++;
فرقی نداره که پیشوند بنویسی یا پسوند، نتیجه یکیه.
ولی بعضی وقتا یکی از این دو شکل خاص لازم میشه.
مثلاً تابع squeeze(s, c) که همهی کاراکترهای c رو از رشتهی s حذف میکنه:
/* squeeze: delete all c from s */
void squeeze(char s[], int c)
{
int i, j;
for (i = j = 0; s[i] != '\0'; i++)
if (s[i] != c)
s[j++] = s[i];
s[j] = '\0';
}
اینجا هر بار که یه کاراکتر غیر از c پیدا میشه، اون کاراکتر در موقعیت فعلی j کپی میشه، و بعد j یکی زیاد میشه تا برای کاراکتر بعدی آماده باشه.
یعنی این دو بخش دقیقاً یکی هستن:
if (s[i] != c)
s[j++] = s[i];
و
if (s[i] != c) {
s[j] = s[i];
j++;
}
یه مثال دیگه از همین نوع در تابع getline از فصل ۱ بود. اونجا میشد این کد:
if (c == '\n') {
s[i] = c;
++i;
}
رو به شکل کوتاهتر نوشت:
if (c == '\n')
s[i++] = c;
یه مثال سوم از کاربرد ++ در تابع استاندارد strcat(s, t) هست، که رشتهی t رو به آخر رشتهی s اضافه میکنه. فرض بر اینه که رشتهی s به اندازهی کافی جا داره.
نسخهی کتابخونهای این تابع یه مقدار برمیگردونه (اشارهگر به رشتهی نتیجه)، ولی نسخهی ما برنمیگردونه.
/* strcat: concatenate t to end of s; s must be big enough */
void strcat(char s[], char t[])
{
int i, j;
i = j = 0;
while (s[i] != '\0') /* find end of s */
i++;
while ((s[i++] = t[j++]) != '\0') /* copy t */
;
}
اینجا بعد از هر بار کپی کردن یه کاراکتر از t به s، عملگر ++ بعد از i و j باعث میشه هر دو به موقعیت بعدی برن تا آمادهی حلقهی بعدی بشن.
تمرین ۴-۲: یه نسخهی جایگزین از تابع squeeze(s1, s2) بنویس که همهی کاراکترهایی از s1 رو حذف کنه که توی رشتهی s2 هم وجود دارن.
تمرین ۵-۲: تابعی بنویس به نام any(s1, s2) که موقعیت اولین کاراکتری از s1 رو برگردونه که توی s2 هم وجود داره، یا اگه هیچکدوم از کاراکترهای s2 توی s1 نیستن، مقدار -1 برگردونه.
(تابع استاندارد strpbrk همین کار رو انجام میده ولی بهجای شمارهی موقعیت، یه اشارهگر به اون مکان برمیگردونه.)