Can You Compare a String to Multiple Values in C?

Navigating string comparisons in C can be tricky, especially when dealing with multiple values; however, COMPARE.EDU.VN offers insightful solutions and comparisons to help you make informed decisions. This in-depth guide explores various techniques, providing clear examples and best practices for efficient string comparison. This guide will cover string literals, comparison operators, conditional statements, and equivalence checks.

Table of Contents

1. Introduction to String Comparison in C

  • 1.1 Understanding Strings in C
  • 1.2 Basic String Comparison Functions

2. The Challenge: Comparing a String to Multiple Values

  • 2.1 Common Scenarios
  • 2.2 Limitations of Basic Comparison

3. Techniques for Comparing a String to Multiple Values in C

  • 3.1 Using if-else Statements
  • 3.2 Using the switch Statement
  • 3.3 Using Arrays and Loops
  • 3.4 Using Function Pointers
  • 3.5 Using Hash Tables

4. Code Examples and Explanations

  • 4.1 Example 1: if-else Implementation
  • 4.2 Example 2: switch Statement Implementation
  • 4.3 Example 3: Array and Loop Implementation
  • 4.4 Example 4: Function Pointer Implementation
  • 4.5 Example 5: Hash Table Implementation

5. Performance Considerations

  • 5.1 Benchmarking Different Methods
  • 5.2 Optimizing String Comparison

6. Best Practices for String Comparison in C

  • 6.1 Case Sensitivity
  • 6.2 Handling Null Strings
  • 6.3 Security Considerations

7. Common Mistakes to Avoid

  • 7.1 Using = Instead of strcmp
  • 7.2 Ignoring Case Sensitivity
  • 7.3 Buffer Overflows

8. Advanced Techniques

  • 8.1 Using Regular Expressions
  • 8.2 Using Libraries for Complex Comparisons

9. Real-World Applications

  • 9.1 Command Parsing
  • 9.2 Data Validation
  • 9.3 Configuration File Handling

10. Tools and Resources

  • 10.1 Debugging Tools
  • 10.2 Online Resources and Documentation

11. COMPARE.EDU.VN: Your Partner in Informed Decision-Making

12. Conclusion

13. FAQs

1. Introduction to String Comparison in C

1.1 Understanding Strings in C

In C, a string is simply an array of characters terminated by a null character . Unlike some other languages, C does not have a built-in string data type. This means that strings are manipulated using pointers and standard library functions. Understanding this fundamental concept is crucial for performing any kind of string operation, including comparison.

char my_string[] = "Hello, World!";

In this example, my_string is an array of characters that holds the value “Hello, World!” followed by a null terminator. The null terminator is what tells C functions where the string ends.

1.2 Basic String Comparison Functions

The C standard library provides several functions for string comparison, the most commonly used being strcmp. This function compares two strings lexicographically and returns an integer value indicating their relationship:

  • 0: If the strings are equal.
  • A negative value: If the first string is less than the second string.
  • A positive value: If the first string is greater than the second string.

Here’s a simple example of how to use strcmp:

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

int main() {
    char str1[] = "apple";
    char str2[] = "banana";
    int result = strcmp(str1, str2);

    if (result == 0) {
        printf("The strings are equal.n");
    } else if (result < 0) {
        printf("str1 is less than str2.n");
    } else {
        printf("str1 is greater than str2.n");
    }

    return 0;
}

In this case, strcmp compares “apple” and “banana” and returns a negative value because “apple” comes before “banana” in lexicographical order.

2. The Challenge: Comparing a String to Multiple Values

2.1 Common Scenarios

Comparing a string to multiple values is a common requirement in many applications. For instance:

  • Command Parsing: An application might need to interpret user commands such as “CREATE”, “READ”, “UPDATE”, or “DELETE”.
  • Data Validation: A program might need to validate user input against a list of acceptable values.
  • Configuration File Handling: An application might need to read configuration parameters from a file and compare them against known options.

2.2 Limitations of Basic Comparison

While strcmp works well for comparing two strings, it becomes cumbersome when you need to compare a single string against multiple values. Using multiple strcmp calls in a series of if-else statements can lead to verbose and less readable code. This approach is also not very scalable when the number of values to compare against increases.

For example:

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

int main() {
    char command[] = "UPDATE";

    if (strcmp(command, "CREATE") == 0) {
        printf("Creating...n");
    } else if (strcmp(command, "READ") == 0) {
        printf("Reading...n");
    } else if (strcmp(command, "UPDATE") == 0) {
        printf("Updating...n");
    } else if (strcmp(command, "DELETE") == 0) {
        printf("Deleting...n");
    } else {
        printf("Invalid command.n");
    }

    return 0;
}

This code works, but it is not efficient or elegant, especially if you have many more commands to handle. This is where more advanced techniques come into play.

3. Techniques for Comparing a String to Multiple Values in C

3.1 Using if-else Statements

The most straightforward approach is to use a series of if-else statements, as shown in the previous example. While simple, this method can become unwieldy for a large number of comparisons. Each additional value requires another strcmp call, making the code longer and harder to maintain.

3.2 Using the switch Statement

Unfortunately, C’s switch statement cannot directly compare strings. The switch statement works with integer values, so you can’t use it directly with strcmp because strcmp returns an integer based on lexicographical comparison, not a constant integer value associated with each string.

3.3 Using Arrays and Loops

A more efficient and scalable approach is to use an array of strings and loop through them, comparing each element to the target string. This method reduces redundancy and makes the code more readable.

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

int main() {
    char command[] = "UPDATE";
    char *valid_commands[] = {"CREATE", "READ", "UPDATE", "DELETE"};
    int num_commands = sizeof(valid_commands) / sizeof(valid_commands[0]);
    int found = 0;

    for (int i = 0; i < num_commands; i++) {
        if (strcmp(command, valid_commands[i]) == 0) {
            printf("Command found: %sn", valid_commands[i]);
            found = 1;
            break;
        }
    }

    if (!found) {
        printf("Invalid command.n");
    }

    return 0;
}

In this example, an array valid_commands holds the valid command strings. The code loops through this array, comparing each command to the input command. This approach is more maintainable and scalable than using multiple if-else statements.

3.4 Using Function Pointers

Function pointers can add another layer of abstraction and flexibility to string comparisons. You can define an array of function pointers, each pointing to a function that handles a specific string comparison.

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

typedef void (*command_handler)(char *);

void create_handler(char *command) {
    printf("Creating: %sn", command);
}

void read_handler(char *command) {
    printf("Reading: %sn", command);
}

void update_handler(char *command) {
    printf("Updating: %sn", command);
}

void delete_handler(char *command) {
    printf("Deleting: %sn", command);
}

int main() {
    char command[] = "UPDATE";
    char *valid_commands[] = {"CREATE", "READ", "UPDATE", "DELETE"};
    command_handler handlers[] = {create_handler, read_handler, update_handler, delete_handler};
    int num_commands = sizeof(valid_commands) / sizeof(valid_commands[0]);
    int found = 0;

    for (int i = 0; i < num_commands; i++) {
        if (strcmp(command, valid_commands[i]) == 0) {
            handlers[i](command);
            found = 1;
            break;
        }
    }

    if (!found) {
        printf("Invalid command.n");
    }

    return 0;
}

In this example, command_handler is a function pointer type. The handlers array holds pointers to functions that handle each command. When a matching command is found, the corresponding handler function is called.

3.5 Using Hash Tables

For a large number of string comparisons, using a hash table can provide significant performance improvements. Hash tables offer average-case O(1) lookup time, making them highly efficient for searching.

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

#define TABLE_SIZE 101

typedef struct {
    char *key;
    void (*handler)(char *);
} HashItem;

HashItem *hash_table[TABLE_SIZE];

unsigned int hash(char *key) {
    unsigned int hashval = 0;
    for (; *key != ''; key++) {
        hashval = *key + 31 * hashval;
    }
    return hashval % TABLE_SIZE;
}

void insert(char *key, void (*handler)(char *)) {
    unsigned int index = hash(key);
    hash_table[index] = malloc(sizeof(HashItem));
    hash_table[index]->key = strdup(key);
    hash_table[index]->handler = handler;
}

void lookup(char *key) {
    unsigned int index = hash(key);
    if (hash_table[index] != NULL && strcmp(hash_table[index]->key, key) == 0) {
        hash_table[index]->handler(key);
    } else {
        printf("Invalid command.n");
    }
}

void create_handler(char *command) {
    printf("Creating: %sn", command);
}

void read_handler(char *command) {
    printf("Reading: %sn", command);
}

void update_handler(char *command) {
    printf("Updating: %sn", command);
}

void delete_handler(char *command) {
    printf("Deleting: %sn", command);
}

int main() {
    // Initialize hash table
    for (int i = 0; i < TABLE_SIZE; i++) {
        hash_table[i] = NULL;
    }

    // Insert commands and handlers
    insert("CREATE", create_handler);
    insert("READ", read_handler);
    insert("UPDATE", update_handler);
    insert("DELETE", delete_handler);

    // Lookup command
    char command[] = "UPDATE";
    lookup(command);

    return 0;
}

In this example, a simple hash table is implemented to map commands to their respective handlers. The hash function computes the hash value for a given string, and the insert function adds the command and handler to the hash table. The lookup function retrieves the handler for a given command.

4. Code Examples and Explanations

4.1 Example 1: if-else Implementation

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

int main() {
    char command[] = "LIST";

    if (strcmp(command, "CREATE") == 0) {
        printf("Creating...n");
    } else if (strcmp(command, "READ") == 0) {
        printf("Reading...n");
    } else if (strcmp(command, "UPDATE") == 0) {
        printf("Updating...n");
    } else if (strcmp(command, "DELETE") == 0) {
        printf("Deleting...n");
    } else if (strcmp(command, "LIST") == 0) {
        printf("Listing...n");
    } else {
        printf("Invalid command.n");
    }

    return 0;
}

Explanation:

  • This example uses a series of if-else statements to compare the command string with multiple possible values.
  • strcmp is used to compare the strings. If the strings match, the corresponding action is performed.
  • If none of the strings match, an “Invalid command” message is printed.

4.2 Example 2: Array and Loop Implementation

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

int main() {
    char command[] = "UPDATE";
    char *valid_commands[] = {"CREATE", "READ", "UPDATE", "DELETE", "LIST"};
    int num_commands = sizeof(valid_commands) / sizeof(valid_commands[0]);
    int found = 0;

    for (int i = 0; i < num_commands; i++) {
        if (strcmp(command, valid_commands[i]) == 0) {
            printf("Command found: %sn", valid_commands[i]);
            found = 1;
            break;
        }
    }

    if (!found) {
        printf("Invalid command.n");
    }

    return 0;
}

Explanation:

  • This example uses an array valid_commands to store a list of valid command strings.
  • A for loop iterates through the array, comparing each command to the input command using strcmp.
  • If a match is found, the loop is exited using break, and a message is printed.
  • If no match is found after iterating through the entire array, an “Invalid command” message is printed.

4.3 Example 3: Function Pointer Implementation

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

typedef void (*command_handler)(char *);

void create_handler(char *command) {
    printf("Creating: %sn", command);
}

void read_handler(char *command) {
    printf("Reading: %sn", command);
}

void update_handler(char *command) {
    printf("Updating: %sn", command);
}

void delete_handler(char *command) {
    printf("Deleting: %sn", command);
}

void list_handler(char *command) {
    printf("Listing: %sn", command);
}

int main() {
    char command[] = "UPDATE";
    char *valid_commands[] = {"CREATE", "READ", "UPDATE", "DELETE", "LIST"};
    command_handler handlers[] = {create_handler, read_handler, update_handler, delete_handler, list_handler};
    int num_commands = sizeof(valid_commands) / sizeof(valid_commands[0]);
    int found = 0;

    for (int i = 0; i < num_commands; i++) {
        if (strcmp(command, valid_commands[i]) == 0) {
            handlers[i](command);
            found = 1;
            break;
        }
    }

    if (!found) {
        printf("Invalid command.n");
    }

    return 0;
}

Explanation:

  • This example uses an array of function pointers to handle different commands.
  • command_handler is a typedef for a function pointer that takes a char * argument and returns void.
  • The handlers array stores pointers to functions that handle each command.
  • The for loop iterates through the valid_commands array, comparing each command to the input command.
  • If a match is found, the corresponding handler function is called.

4.4 Example 4: Hash Table Implementation

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

#define TABLE_SIZE 101

typedef struct {
    char *key;
    void (*handler)(char *);
} HashItem;

HashItem *hash_table[TABLE_SIZE];

unsigned int hash(char *key) {
    unsigned int hashval = 0;
    for (; *key != ''; key++) {
        hashval = *key + 31 * hashval;
    }
    return hashval % TABLE_SIZE;
}

void insert(char *key, void (*handler)(char *)) {
    unsigned int index = hash(key);
    hash_table[index] = malloc(sizeof(HashItem));
    hash_table[index]->key = strdup(key);
    hash_table[index]->handler = handler;
}

void lookup(char *key) {
    unsigned int index = hash(key);
    if (hash_table[index] != NULL && strcmp(hash_table[index]->key, key) == 0) {
        hash_table[index]->handler(key);
    } else {
        printf("Invalid command.n");
    }
}

void create_handler(char *command) {
    printf("Creating: %sn", command);
}

void read_handler(char *command) {
    printf("Reading: %sn", command);
}

void update_handler(char *command) {
    printf("Updating: %sn", command);
}

void delete_handler(char *command) {
    printf("Deleting: %sn", command);
}

void list_handler(char *command) {
    printf("Listing: %sn", command);
}

int main() {
    // Initialize hash table
    for (int i = 0; i < TABLE_SIZE; i++) {
        hash_table[i] = NULL;
    }

    // Insert commands and handlers
    insert("CREATE", create_handler);
    insert("READ", read_handler);
    insert("UPDATE", update_handler);
    insert("DELETE", delete_handler);
    insert("LIST", list_handler);

    // Lookup command
    char command[] = "UPDATE";
    lookup(command);

    return 0;
}

Explanation:

  • This example implements a simple hash table to map commands to their respective handlers.
  • TABLE_SIZE defines the size of the hash table.
  • HashItem is a struct that contains the command string (key) and a function pointer (handler).
  • hash function computes the hash value for a given string.
  • insert function adds the command and handler to the hash table.
  • lookup function retrieves the handler for a given command.

5. Performance Considerations

5.1 Benchmarking Different Methods

When choosing a method for comparing a string to multiple values, it’s important to consider performance. Here’s a brief overview of the performance characteristics of each method:

Method Performance Characteristics
if-else Statements O(n) in the worst case, where n is the number of comparisons.
Arrays and Loops O(n), where n is the number of elements in the array.
Function Pointers Similar to arrays and loops, O(n), but with added overhead of function calls.
Hash Tables Average case O(1), but worst-case O(n) if there are many collisions. Requires additional memory for the hash table.

For a small number of comparisons, the if-else method or arrays and loops may be sufficient. However, for a large number of comparisons, hash tables generally offer the best performance.

5.2 Optimizing String Comparison

Several techniques can be used to optimize string comparison in C:

  • Use strncmp for Partial Comparisons: If you only need to compare the first few characters of a string, strncmp can be more efficient than strcmp.
  • Cache Hash Values: If you are using hash tables, cache the hash values to avoid recomputing them repeatedly.
  • Minimize String Duplication: Avoid creating unnecessary copies of strings, as this can consume memory and slow down your program.

6. Best Practices for String Comparison in C

6.1 Case Sensitivity

By default, strcmp is case-sensitive. If you need to perform case-insensitive comparisons, you can use the strcasecmp function (which is not part of the C standard library but is available on many systems) or convert the strings to the same case before comparing them.

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

int strcasecmp_custom(const char *s1, const char *s2) {
    while (*s1 != '' && *s2 != '') {
        int diff = tolower((unsigned char)*s1) - tolower((unsigned char)*s2);
        if (diff != 0) {
            return diff;
        }
        s1++;
        s2++;
    }
    return tolower((unsigned char)*s1) - tolower((unsigned char)*s2);
}

int main() {
    char str1[] = "Hello";
    char str2[] = "hello";

    if (strcasecmp_custom(str1, str2) == 0) {
        printf("The strings are equal (case-insensitive).n");
    } else {
        printf("The strings are not equal (case-insensitive).n");
    }

    return 0;
}

6.2 Handling Null Strings

Always check for null strings before attempting to compare them. Passing a null pointer to strcmp will result in undefined behavior.

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

int main() {
    char *str1 = NULL;
    char str2[] = "hello";

    if (str1 == NULL) {
        printf("str1 is NULL.n");
    } else if (strcmp(str1, str2) == 0) {
        printf("The strings are equal.n");
    } else {
        printf("The strings are not equal.n");
    }

    return 0;
}

6.3 Security Considerations

When working with strings, be aware of potential security vulnerabilities such as buffer overflows. Always ensure that your buffers are large enough to hold the strings you are working with. Functions like strncpy can help prevent buffer overflows by limiting the number of characters copied.

7. Common Mistakes to Avoid

7.1 Using = Instead of strcmp

One of the most common mistakes is using the = operator to compare strings. In C, = compares the memory addresses of the strings, not their contents. Always use strcmp to compare the contents of strings.

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

int main() {
    char str1[] = "hello";
    char str2[] = "hello";

    if (str1 == str2) { // Incorrect: compares memory addresses
        printf("The strings are equal.n");
    } else {
        printf("The strings are not equal.n");
    }

    if (strcmp(str1, str2) == 0) { // Correct: compares string contents
        printf("The strings are equal.n");
    } else {
        printf("The strings are not equal.n");
    }

    return 0;
}

7.2 Ignoring Case Sensitivity

Forgetting that strcmp is case-sensitive can lead to unexpected results. If case-insensitive comparisons are needed, use strcasecmp or convert the strings to the same case before comparing.

7.3 Buffer Overflows

Writing beyond the bounds of a buffer can lead to crashes or security vulnerabilities. Always use safe functions like strncpy to avoid buffer overflows.

8. Advanced Techniques

8.1 Using Regular Expressions

For more complex string matching requirements, you can use regular expressions. The regex.h library provides functions for working with regular expressions in C.

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

int main() {
    char *string = "Hello, World!";
    char *pattern = "Hello.*";
    regex_t regex;
    int return_value;

    // Compile regular expression
    return_value = regcomp(&regex, pattern, 0);
    if (return_value) {
        fprintf(stderr, "Could not compile regexn");
        exit(1);
    }

    // Execute regular expression
    return_value = regexec(&regex, string, 0, NULL, 0);
    if (!return_value) {
        printf("Match found.n");
    } else if (return_value == REG_NOMATCH) {
        printf("No match found.n");
    } else {
        fprintf(stderr, "Regex match failed.n");
        exit(1);
    }

    // Free memory used by regular expression
    regfree(&regex);

    return 0;
}

8.2 Using Libraries for Complex Comparisons

Several libraries provide more advanced string comparison capabilities, such as fuzzy string matching and phonetic matching. These libraries can be useful for applications that need to handle misspellings or variations in string input.

9. Real-World Applications

9.1 Command Parsing

Many applications use string comparison to parse user commands. For example, a command-line tool might use string comparison to determine which action to take based on the user’s input.

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

int main(int argc, char *argv[]) {
    if (argc < 2) {
        printf("Usage: command <action>n");
        return 1;
    }

    char *action = argv[1];

    if (strcmp(action, "create") == 0) {
        printf("Creating...n");
    } else if (strcmp(action, "read") == 0) {
        printf("Reading...n");
    } else if (strcmp(action, "update") == 0) {
        printf("Updating...n");
    } else if (strcmp(action, "delete") == 0) {
        printf("Deleting...n");
    } else {
        printf("Invalid action.n");
    }

    return 0;
}

9.2 Data Validation

String comparison is often used to validate user input. For example, a program might check that a user-entered string matches a specific format or is one of a set of valid values.

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

int main() {
    char input[100];
    printf("Enter a color (red, green, blue): ");
    fgets(input, sizeof(input), stdin);
    input[strcspn(input, "n")] = 0; // Remove newline character

    if (strcmp(input, "red") == 0 || strcmp(input, "green") == 0 || strcmp(input, "blue") == 0) {
        printf("Valid color.n");
    } else {
        printf("Invalid color.n");
    }

    return 0;
}

9.3 Configuration File Handling

String comparison is used to read and interpret configuration files. For example, an application might read key-value pairs from a configuration file and use string comparison to determine the value associated with a particular key.

10. Tools and Resources

10.1 Debugging Tools

  • GDB (GNU Debugger): A powerful command-line debugger that allows you to step through your code, inspect variables, and set breakpoints.
  • Valgrind: A memory debugging tool that can help you detect memory leaks and other memory-related errors.

10.2 Online Resources and Documentation

  • cplusplus.com: A comprehensive resource for C and C++ programming, with detailed documentation and examples.
  • Stack Overflow: A question-and-answer site where you can find solutions to common programming problems and get help from other developers.

11. COMPARE.EDU.VN: Your Partner in Informed Decision-Making

At COMPARE.EDU.VN, we understand the challenges of making informed decisions in a complex world. That’s why we provide detailed comparisons and objective evaluations across a wide range of products, services, and ideas. Whether you’re comparing different programming techniques, evaluating consumer products, or assessing educational resources, COMPARE.EDU.VN is your go-to source for reliable information.

We offer comprehensive analyses, clear comparisons, and user reviews to help you make the right choices. Our goal is to empower you with the knowledge you need to confidently navigate your options and achieve your objectives.

12. Conclusion

Comparing a string to multiple values in C can be achieved through various techniques, each with its own advantages and disadvantages. Whether you choose to use if-else statements, arrays and loops, function pointers, or hash tables depends on the specific requirements of your application. Understanding the performance characteristics, best practices, and common pitfalls associated with each method will help you write efficient, maintainable, and secure code.

Remember, COMPARE.EDU.VN is here to assist you with making informed decisions. If you’re facing a tough choice, visit our website for comprehensive comparisons and expert insights.

For more information or assistance, please contact us at:

  • Address: 333 Comparison Plaza, Choice City, CA 90210, United States
  • WhatsApp: +1 (626) 555-9090
  • Website: COMPARE.EDU.VN

13. FAQs

Q1: Can I use a switch statement to compare strings in C?
A: No, C’s switch statement cannot directly compare strings. It works with integer values, so you can’t use it directly with strcmp.

Q2: What is the best way to compare a string to multiple values in C?
A: The best method depends on the number of values you need to compare against. For a small number of values, if-else statements or arrays and loops may be sufficient. For a large number of values, hash tables generally offer the best performance.

Q3: How can I perform case-insensitive string comparisons in C?
A: You can use the strcasecmp function (if available on your system) or convert the strings to the same case before comparing them.

Q4: What is strcmp in C?
A: strcmp is a C standard library function used to compare two strings lexicographically. It returns 0 if the strings are equal, a negative value if the first string is less than the second string, and a positive value if the first string is greater than the second string.

Q5: What are some common mistakes to avoid when comparing strings in C?
A: Common mistakes include using = instead of strcmp, ignoring case sensitivity, and not handling null strings.

Q6: How can I prevent buffer overflows when working with strings in C?
A: Use safe functions like strncpy to limit the number of characters copied, and always ensure that your buffers are large enough to hold the strings you are working with.

Q7: What are function pointers and how can they be used in string comparison?
A: Function pointers are variables that store the address of a function. They can be used to create arrays of functions, allowing you to call different functions based on string comparison results.

Q8: What is a hash table and how can it improve string comparison performance?
A: A hash table is a data structure that maps keys to values using a hash function. It can provide average-case O(1) lookup time, making it highly efficient for searching and comparing strings.

Q9: How can regular expressions be used in string comparison in C?
A: Regular expressions provide a powerful way to perform complex pattern matching on strings. The regex.h library provides functions for working with regular expressions in C.

Q10: Where can I find more information and resources on string comparison in C?
A: You can find more information and resources on sites like cplusplus.com, Stack Overflow, and in various C programming books and tutorials. Also, check out COMPARE.EDU.VN for comparisons of different methods and tools.

Ready to make informed decisions? Visit compare.edu.vn today to explore detailed comparisons and expert insights that will help you choose the best solutions for your needs.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *