برق و الکترونیک *دانلود پروژه رایگان
2.28K subscribers
784 photos
96 videos
350 files
641 links
بسمه تعالی
دانلود پروژه و پی سی بی رایگان
Download Telegram
یک تابع به زبان C مینویسیم که تعداد مشخصی از کاراکترها را از ابتدا و انتهای یک رشته حذف کرده و رشته جدید را برگرداند. این تابع مواردی مانند مقادیر منفی یا بزرگتر از طول رشته را نیز مدیریت میکند.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char* trim_string(const char* str, int n, int m) {
if (str == NULL) {
return NULL;
}

int len = strlen(str);

// اطمینان از عدم منفی بودن n و m
n = (n < 0) ? 0 : n;
m = (m < 0) ? 0 : m;

// محدود کردن n و m به طول رشته
if (n > len) {
n = len;
}
if (m > (len - n)) {
m = len - n;
}

int new_len = len - n - m;
char* result = (char*)malloc(new_len + 1); // +1 برای نال ترمیناتور
if (result == NULL) {
return NULL;
}

// کپی بخش مورد نظر از رشته اصلی
memcpy(result, str + n, new_len);
result[new_len] = '\0'; // پایان رشته

return result;
}

// مثال استفاده از تابع
int main() {
const char* str = "Hello, World!";
int n = 3;
int m = 4;

char* trimmed = trim_string(str, n, m);
if (trimmed != NULL) {
printf("Original: %s\n", str);
printf("Trimmed (%d from start, %d from end): '%s'\n", n, m, trimmed);
free(trimmed); // آزادسازی حافظه
}

// تست موارد خاص
char* test1 = trim_string("Example", 0, 0);
printf("\nTest 1: '%s'\n", test1);
free(test1);

char* test2 = trim_string("Test", 5, 2);
printf("Test 2: '%s'\n", test2);
free(test2);

char* test3 = trim_string("Hello", 1, 1);
printf("Test 3: '%s'\n", test3);
free(test3);

return 0;
}

### توضیحات:
1. ورودی تابع: رشته اصلی (str)، تعداد کاراکترهای حذف از ابتدا (n)، و تعداد کاراکترهای حذف از انتها (m).
2. بررسی مقادیر منفی: اگر n یا m منفی باشند، به صورت خودکار صفر در نظر گرفته میشوند.
3. محدود کردن مقادیر: اگر n یا m از طول رشته بیشتر باشند، به حداکثر مقدار ممکن محدود میشوند.
4. محاسبه طول جدید: طول رشته جدید پس از حذف کاراکترها محاسبه میشود.
5. اختصاص حافظه: حافظه لازم برای رشته جدید همراه با نال ترمیناتور اختصاص مییابد.
6. کپی بخش مورد نظر: بخش مربوطه از رشته اصلی به رشته جدید کپی میشود.
7. خروجی: رشته جدید برگردانده میشود که باید توسط کاربر آزاد شود.

### مثال خروجی:
Original: Hello, World!
Trimmed (3 from start, 4 from end): 'lo, Wo'

Test 1: 'Example'
Test 2: ''
Test 3: 'ell'

این تابع تمام حالات مرزی مانند رشته خالی، مقادیر منفی، یا مقادیر بزرگتر از طول رشته را به درستی مدیریت میکند.
برای پیادهسازی تابع split در زبان C که یک رشته را بر اساس یک جداکننده تقسیم میکند، میتوان از روش زیر استفاده کرد. این تابع تمام توکنها از جمله توکنهای خالی را در نظر میگیرد و آرایهای از رشتههای تقسیمشده را برمیگرداند.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char** split(const char* str, char separator, int* count) {
int len = strlen(str);
int num_separators = 0;

// شمارش تعداد جداکنندهها
for (int i = 0; i < len; i++) {
if (str[i] == separator) {
num_separators++;
}
}

// محاسبه تعداد توکنها
int num_tokens = (len == 0) ? 0 : num_separators + 1;
if (num_tokens == 0) {
*count = 0;
return NULL;
}

// ذخیره اندیسهای جداکنندهها
int* separator_indices = malloc(num_separators * sizeof(int));
if (!separator_indices) {
return NULL;
}

int idx = 0;
for (int i = 0; i < len; i++) {
if (str[i] == separator) {
separator_indices[idx++] = i;
}
}

// اختصاص حافظه برای آرایه توکنها
char** tokens = malloc((num_tokens + 1) * sizeof(char*));
if (!tokens) {
free(separator_indices);
return NULL;
}

int token_index = 0;
int start = 0;

// استخراج توکنها بین جداکنندهها
for (int i = 0; i < num_separators; i++) {
int end = separator_indices[i] - 1;
int token_length = end - start + 1;
char* token = malloc(token_length + 1); // +1 برای نال ترمیناتور
if (!token) {
// آزادسازی حافظه در صورت خطا
for (int j = 0; j < token_index; j++) {
free(tokens[j]);
}
free(tokens);
free(separator_indices);
return NULL;
}
if (token_length > 0) {
strncpy(token, str + start, token_length);
}
token[token_length] = '\0';
tokens[token_index++] = token;
start = separator_indices[i] + 1;
}

// آخرین توکن بعد از آخرین جداکننده
int end = len - 1;
int token_length = end - start + 1;
char* token = malloc(token_length + 1);
if (!token) {
for (int j = 0; j < token_index; j++) {
free(tokens[j]);
}
free(tokens);
free(separator_indices);
return NULL;
}
if (token_length > 0) {
strncpy(token, str + start, token_length);
}
token[token_length] = '\0';
tokens[token_index++] = token;

// پایان آرایه با NULL
tokens[token_index] = NULL;
free(separator_indices);

*count = num_tokens;
return tokens;
}

// تابع برای آزاد کردن حافظه اختصاصدادهشده توسط split
void free_split_result(char** tokens) {
if (tokens) {
for (int i = 0; tokens[i] != NULL; i++) {
free(tokens[i]);
}
free(tokens);
}
}

// مثال استفاده از تابع
int main() {
const char* str = "hello,,world";
char separator = ',';
int count;
char** tokens = split(str, separator, &count);

if (tokens) {
printf("تعداد توکنها: %d\n", count);
for (int i = 0; i < count; i++) {
printf("توکن %d: '%s'\n", i, tokens[i]);
}
free_split_result(tokens);
}

return 0;
}

### توضیحات:
1. شمارش جداکنندهها: ابتدا تعداد جداکنندهها در رشته اصلی شمارش میشود.
2. محاسبه تعداد توکنها: تعداد توکنها برابر با تعداد جداکنندهها بهعلاوه یک است. اگر رشته خالی باشد، تعداد توکنها صفر در نظر گرفته میشود.
3. ذخیره اندیس جداکنندهها: اندیسهای تمام جداکنندهها در یک آرایه ذخیره میشوند.
4. استخراج توکنها: توکنها بین اندیسهای جداکنندهها استخراج میشوند. هر توکن شامل کاراکترهای بین دو جداکننده متوالی است.
5. آزادسازی حافظه: بعد از استفاده از توکنها، باید حافظه اختصاصدادهشده توسط تابع split با استفاده از تابع free_split_result آزاد شود.

### مثال خروجی:
برای رشته ورودی "hello,,world" با جداکننده ','، خروجی به صورت زیر خواهد بود:
تعداد توکنها: 3
توکن 0: 'hello'
توکن 1: ''
توکن 2: 'world'

این تابع تمام حالات از جمله توکنهای خالی در ابتدا، انتها یا بین جداکنندهها را بهدرستی پردازش میکند.
بیایید با جزئیات کامل به آموزش تابع sscanf در زبان C بپردازیم. این تابع برای خواندن دادههای قالببندیشده از یک رشته (String) استفاده میشود و شباهت زیادی به تابع scanf دارد، با این تفاوت که بهجای خواندن از ورودی استاندارد (مانند صفحهکلید)، از یک رشته بهعنوان منبع داده استفاده میکند.

---

### **۱. ساختار تابع sscanf**
int sscanf(const char *str, const char *format, ...);

- **پارامترها:**
- str: رشته ورودی که دادهها از آن خوانده میشوند.
- format: رشته فرمت که مشخص میکند چگونه دادهها خوانده شوند.
- ...: متغیرهای آدرسی که دادههای خواندهشده در آنها ذخیره میشمقدار بازگشتی:زگشتی:**
- تعداد متغیرهایی که با موفقیت خوانده شدهاند.
- اگر خطایی رخ دهد، EOF برمیگرداند.

-۲. مثالهای پایهی پایه**
#### مثال ۱: خواندن یک عدد صحیح از رشته
#include <stdio.h>

int main() {
char input[] = "42";
int num;

int result = sscanf(input, "%d", &num);

printf("خوانده شده: %d\n", num); // خروجی: 42
printf("تعداد متغیرهای خواندهشده: %d\n", result); // خروجی: 1

return 0;
}

#### مثال ۲: خواندن چند متغیر با انواع مختلف
#include <stdio.h>

int main() {
char input[] = "Ali 25 75.5";
char name[50];
int age;
float score;

int result = sscanf(input, "%s %d %f", name, &age, &score);

printf("نام: %s\n", name); // Ali
printf("سن: %d\n", age); // 25
printf("امتیاز: %.1f\n", score); // 75.5
printf("تعداد خواندهشده: %d\n", result); // 3

return 0;
}

-۳. خواندن دادههای پیچیدهترچیدهتر**
#### مثال ۳: خواندن تاریخ با فرمت مشخص (dd/mm/yyyy)
#include <stdio.h>

int main() {
char input[] = "31/12/2023";
int day, month, year;

int result = sscanf(input, "%d/%d/%d", &day, &month, &year);

printf("تاریخ: %d-%d-%d\n", day, month, year); // 31-12-2023
printf("تعداد خواندهشده: %d\n", result); // 3

return 0;
}

#### مثال ۴: خواندن بخشی از رشته با استWidth Specifiercifier**
#include <stdio.h>

int main() {
char input[] = "1234567890";
char first_part[5];
int num;

// خواندن ۴ کاراکتر اول و سپس یک عدد
sscanf(input, "%4s%d", first_part, &num);

printf("بخش اول: %s\n", first_part); // 1234
printf("عدد: %d\n", num); // 567890

return 0;
}

-۴. کار با کاراکترهای خاصای خاص**
#### مثال ۵: خواندن تا رسیدن به یک کاراکتر خاص (با استفاده از %[^])
#include <stdio.h>

int main() {
char input[] = "apple,banana,cherry";
char fruits[3][20];

// خواندن تا ویرگول
sscanf(input, "%[^,],%[^,],%s", fruits[0], fruits[1], fruits[2]);

printf("میوه ۱: %s\n", fruits[0]); // apple
printf("میوه ۲: %s\n", fruits[1]); // banana
printf("میوه ۳: %s\n", fruits[2]); // cherry

return 0;
}

#### مثال ۶: نادیده گرفتن کاراکترهای خاص (با استفاده از *)
#include <stdio.h>

int main() {
char input[] = "Product: 1234 Price: 99.99$";
int id;
float price;

// نادیده گرفتن کلمه "Product:" و خواندن عدد
sscanf(input, "Product: %d Price: %f$", &id, &price);

printf("شناسه: %d\n", id); // 1234
printf("قیمت: %.2f\n", price); // 99.99

return 0;
}

-۵. کنترل خطاها و اعتبارسنجیارسنجی**
#### مثال ۷: بررسی موفقیت عملیات با مقدار بازگشتی
#include <stdio.h>

int main() {
char input[] = "Error: Invalid Data";
int code;

int result = sscanf(input, "Error: %d", &code);

if (result == 1) {
printf("کد خطا: %d\n", code);
} else {
printf("فرمت رشته نادرست است!\n"); // این خط اجرا میشود
}

return 0;
}

-۶. خواندن دادههای پیشرفتهیشرفته**
#### مثال ۸: خواندن اعداد هگزادسیمال (با %x)
#include <stdio.h>

int main() {
char input[] = "Color: #FF5733";
unsigned int color;

sscanf(input, "Color: #%x", &color);

printf("مقدار هگز: %X\n", color); // FF5733

return 0;
}

#### مثال ۹: خواندن با استScansetcanset** (%[])
`c
#include <stdio.h>

int main() {
char input[] = "Username: User123!";
char username[20];

// خواندن فقط حروف و اعداد (تا رسیدن به کاراکتر غیرمجاز)
sscanf(input, "Username: %[A-Za-z0-9]", username);
printf("نام کاربری: %s\n", username); // User123

return 0;
}

---

### **۷. اشتباهات رایج**
#### خطا ۱: عدم استفاده از `&` برای متغیرها

c
int num;
// غلط: sscanf(input, "%d", num);
// صحیح: sscanf(input, "%d", &num);

#### خطا ۲: عدم تطابق فرمت و دادهها

c
char input[] = "Hello";
int num;

// غلط: sscanf(input, "%d", &num); // خطای Undefined Behavior
`

---

۸. جدول فرمتهاها**
| فرمت | توضیح | مثال |
|--------|--------------------------------|-------------|
| `%d` | عدد صحیح (`int`) | `-42` |
| `%f` | عدد اعشاری (`float`) | `3.14` |
| `%lf` | عدد اعشاری (`double`) | `2.71828` |
| `%c` | یک کاراکتر | `'A'` |
| `%s` | رشته (تا فاصله یا خط جدید) | `"Hello"` |
| `%[^,]`| خواندن تا ویرگول | `"apple,"` |
| `%x` | عدد هگزادسیمال | `"1A3F"` |
| `%%` | خواندن کاراکتر `%` | `"50%"` |

---

۹. جمعبندیدی**
- `sscanf` برای تجزیه (Parse) دادهها از رشتهها بسیار قدرتمند است.
- هممقدار بازگشتیتی** را بررسی کنید تا از موفقیت عملیات مطمئن شوید.
- برای جلوگیری از خطاهایی ماBuffer Overflowow**، از Width Specifier (مثلاً `%9s` برای آرایه ۱۰ کاراکتری) استفاده کنید.
یک تابع در زبان C مینویسیم که تعداد متغیری از رشتهها را دریافت کرده و آنها را به هم متصل میکند. برای مدیریت پارامترهای متغیر از کتابخانه stdarg.h استفاده میکنیم. در این روش، لیست رشتهها با یک NULL خاتمه مییابد تا تابع تشخیص دهد چه زمانی باید پردازش را متوقف کند.

### کد نهایی:
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char* concatenate(const char* first, ...) {
if (first == NULL) {
char* result = malloc(1);
if (result) *result = '\0';
return result;
}

va_list args;
size_t total_length = 0;
const char* current = first;

// محاسبه طول کل تمام رشته‌ها
va_start(args, first);
do {
total_length += strlen(current);
current = va_arg(args, const char*);
} while (current != NULL);
va_end(args);

// اختصاص حافظه برای رشته نهایی
char* result = (char*)malloc(total_length + 1);
if (!result) return NULL;

char* ptr = result;

// الحاق رشته‌ها
va_start(args, first);
current = first;
do {
size_t len = strlen(current);
memcpy(ptr, current, len);
ptr += len;
current = va_arg(args, const char*);
} while (current != NULL);
va_end(args);

*ptr = '\0'; // پایان‌دهی رشته

return result;
}

// مثال استفاده از تابع
int main() {
char* str = concatenate("Hello", " ", "World!", NULL);
if (str) {
printf("%s\n", str); // خروجی: Hello World!
free(str);
}

str = concatenate("C", " ", "Programming", " ", "Language", NULL);
if (str) {
printf("%s\n", str); // خروجی: C Programming Language
free(str);
}

return 0;
}

### شرح کد:
1. محاسبه طول کل رشتهها: با استفاده از va_list و حلقه do-while، طول تمام رشتهها را جمع میزنیم تا حافظه لازم را اختصاص دهیم.
2. اختصاص حافظه: با توجه به طول کل محاسبهشده، حافظه مورد نیاز را اختصاص میدهیم.
3. الحاق رشتهها: دوباره از va_list استفاده کرده و هر رشته را به ترتیب به رشته نهایی اضافه میکنیم.
4. اتمام رشته: در انتها کاراکتر نول ('\0') را اضافه میکنیم تا رشته به درستی خاتمه یابد.

### نکات مهم:
- اگر اولین رشته NULL باشد، تابع یک رشته خالی برمیگرداند.
- کاربر باید آخرین آرگومان را NULL قرار دهد تا پایان لیست رشتهها مشخص شود.
- حافظه بازگشتی توسط تابع باید توسط کاربر آزاد شود (free()).
یک تابع در زبان C مینویسیم که دو رشته را دریافت کرده و بررسی میکند آیا رشته دوم درون رشته اول وجود دارد یا خیر. اگر وجود داشت، موقعیت اولین وقوع آن را برمیگرداند. در غیر این صورت مقدار -1 را بازمیگرداند.

### کد نهایی:
#include <stdio.h>
#include <string.h>

int findSubstring(const char *str1, const char *str2) {
// اگر رشته دوم خالی باشد، موقعیت 0 برگردانده میشود
if (*str2 == '\0') {
return 0;
}

int len1 = strlen(str1);
int len2 = strlen(str2);

// اگر طول رشته دوم از رشته اول بیشتر باشد، قطعا وجود ندارد
if (len2 > len1) {
return -1;
}

// بررسی تمام موقعیتهای ممکن در رشته اول
for (int i = 0; i <= len1 - len2; i++) {
// اگر کاراکتر اول تطابق داشت، بقیه را بررسی کن
if (str1[i] == str2[0]) {
int match = 1;
for (int j = 1; j < len2; j++) {
if (str1[i + j] != str2[j]) {
match = 0;
break;
}
}
// اگر تمام کاراکترها تطابق داشتند
if (match) {
return i;
}
}
}

// اگر هیچ تطابقی یافت نشد
return -1;
}

// مثال استفاده از تابع
int main() {
const char *str1 = "hello world";
const char *str2 = "world";

int position = findSubstring(str1, str2);
if (position != -1) {
printf("زیررشته در موقعیت %d یافت شد.\n", position); // خروجی: 6
} else {
printf("زیررشته یافت نشد.\n");
}

return 0;
}

### شرح کد:
1. بررسی حالتهای خاص:
- اگر رشته دوم خالی باشد (str2 == "")، موقعیت 0 برگردانده میشود.
- اگر طول رشته دوم از رشته اول بیشتر باشد، بلافاصله -1 برگردانده میشود.

2. حلقه بیرونی:
- تمام موقعیتهای ممکن در رشته اول را بررسی میکند (تا جایی که جای کافی برای رشته دوم باقی مانده باشد).

3. حلقه داخلی:
- اگر کاراکتر اول رشته دوم با موقعیت فعلی در رشته اول تطابق داشت، بقیه کاراکترها را مقایسه میکند.
- اگر تمام کاراکترهای رشته دوم با بخشی از رشته اول مطابقت داشت، موقعیت آن را برمیگرداند.

4. مقدار بازگشتی:
- اگر زیررشته یافت نشد، مقدار -1 برگردانده میشود.

### مثالهای تست:
- findSubstring("hello", "ll")2
- findSubstring("abc", "abcd")-1
- findSubstring("", "")0
- findSubstring("apple", "app")0

### نکات مهم:
- این تابع حسّاس به بزرگی و کوچکی حروف است.
- موقعیتها از ایندکس 0 شمارش میشوند.
- اگر رشته دوم چندبار در رشته اول تکرار شده باشد، موقعیت اولین وقوع برگردانده میشود.