C语言结构体数组问题:构建规则字典及实现文本内容替换
Step 1: Properly Populate Your Rule Dictionary
First, your make_dic() function has allocated memory for the Rule array, but you haven't filled it with the key-value pairs from your rule file. Here's how to parse lines like abc=123 and populate the dictionary correctly:
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct rule { char* old; char* new; } Rule; int count_rules() { // Counts valid rule lines (skips empty lines/comments) FILE* fp = fopen("rules.txt", "r"); if (!fp) return 0; int count = 0; char line[256]; while (fgets(line, sizeof(line), fp)) { if (line[0] == '\n' || line[0] == '#') continue; count++; } fclose(fp); return count; } void make_dic(Rule** dictionary, int* amount_rules) { *amount_rules = count_rules(); if (*amount_rules == 0) { *dictionary = NULL; return; } *dictionary = malloc(*amount_rules * sizeof(Rule)); if (!*dictionary) { perror("malloc failed for dictionary"); *amount_rules = 0; return; } FILE* fp = fopen("rules.txt", "r"); if (!fp) { perror("failed to open rules file"); free(*dictionary); *dictionary = NULL; *amount_rules = 0; return; } char line[256]; int idx = 0; while (fgets(line, sizeof(line), fp) && idx < *amount_rules) { if (line[0] == '\n' || line[0] == '#') continue; // Remove newline character line[strcspn(line, "\n")] = '\0'; // Split line at '=' char* eq_pos = strchr(line, '='); if (!eq_pos) { fprintf(stderr, "Invalid rule line: %s\n", line); continue; } *eq_pos = '\0'; char* old_str = line; char* new_str = eq_pos + 1; // Trim leading/trailing whitespace (optional but useful) while (*old_str == ' ') old_str++; char* end = old_str + strlen(old_str) - 1; while (end > old_str && *end == ' ') end--; *(end + 1) = '\0'; while (*new_str == ' ') new_str++; end = new_str + strlen(new_str) - 1; while (end > new_str && *end == ' ') end--; *(end + 1) = '\0'; // Allocate and copy strings to Rule (*dictionary)[idx].old = strdup(old_str); (*dictionary)[idx].new = strdup(new_str); // Handle allocation failures if (!(*dictionary)[idx].old || !(*dictionary)[idx].new) { fprintf(stderr, "Memory allocation failed for rule %d\n", idx); for (int i = 0; i < idx; i++) { free((*dictionary)[i].old); free((*dictionary)[i].new); } free(*dictionary); *dictionary = NULL; *amount_rules = 0; fclose(fp); return; } idx++; } fclose(fp); }
Step 2: Implement Text Replacement Logic
Next, create a helper function to replace all occurrences of a string, then apply every rule to your target text file:
// Replace all instances of old_str with new_str in src char* replace_all(const char* src, const char* old_str, const char* new_str) { if (!src || !old_str || !new_str) return NULL; size_t old_len = strlen(old_str); size_t new_len = strlen(new_str); if (old_len == 0) return strdup(src); // Count occurrences to calculate buffer size int count = 0; const char* temp = src; while ((temp = strstr(temp, old_str)) != NULL) { count++; temp += old_len; } size_t result_len = strlen(src) + count * (new_len - old_len) + 1; char* result = malloc(result_len); if (!result) return NULL; char* ptr = result; temp = src; while ((temp = strstr(temp, old_str)) != NULL) { size_t copy_len = temp - src; strncpy(ptr, src, copy_len); ptr += copy_len; strcpy(ptr, new_str); ptr += new_len; src = temp + old_len; temp = src; } strcpy(ptr, src); return result; } // Process target text file with all rules void process_text_file(const char* input_path, const char* output_path, Rule* dictionary, int amount_rules) { FILE* in_fp = fopen(input_path, "r"); if (!in_fp) { perror("failed to open input file"); return; } FILE* out_fp = fopen(output_path, "w"); if (!out_fp) { perror("failed to open output file"); fclose(in_fp); return; } char line[1024]; while (fgets(line, sizeof(line), in_fp)) { line[strcspn(line, "\n")] = '\0'; char* current_line = strdup(line); if (!current_line) { fprintf(stderr, "Memory allocation failed for line\n"); continue; } // Apply every rule to the line for (int i = 0; i < amount_rules; i++) { char* replaced_line = replace_all(current_line, dictionary[i].old, dictionary[i].new); if (!replaced_line) { fprintf(stderr, "Replacement failed for rule %d\n", i); free(current_line); current_line = strdup(line); continue; } free(current_line); current_line = replaced_line; } fprintf(out_fp, "%s\n", current_line); free(current_line); } fclose(in_fp); fclose(out_fp); }
Step 3: Clean Up Memory
Always free allocated memory to avoid leaks:
void free_dictionary(Rule* dictionary, int amount_rules) { if (!dictionary) return; for (int i = 0; i < amount_rules; i++) { free(dictionary[i].old); free(dictionary[i].new); } free(dictionary); }
Example Main Function
Put it all together with a main function:
int main() { Rule* dictionary = NULL; int amount_rules = 0; make_dic(&dictionary, &amount_rules); if (amount_rules == 0 || !dictionary) { fprintf(stderr, "No valid rules loaded\n"); return 1; } process_text_file("input.txt", "output.txt", dictionary, amount_rules); free_dictionary(dictionary, amount_rules); return 0; }
Key Notes
- Rule File Flexibility: The code skips empty lines and comment lines (starting with
#) — adjust this if your rule file uses a different format. - Whitespace Handling: Trimming whitespace from rule keys/values ensures replacements work even if lines have spaces like
abc = 123. - Edge Case Safety: The replacement function handles multiple occurrences of a key in one line, and falls back to the original line if any replacement fails.
- Memory Safety: All allocations are checked, and we clean up all memory properly after use.
内容的提问来源于stack exchange,提问作者MirEso
相关产品推荐
相关产品推荐

