Search code examples
cregexgetlinec-stringsstring-literals

C - can I create a const char * variable from char *?


The reason why I would want to do this is because I want to read from a file line-by-line, and for each line check whether it matches a regex. I am using the getline() function, which puts the line into a char * type variable. I am trying to use regexec() to check for a regex match, but this function wants you to provide the string to match as a const char *.

So my question is, can I create a const char * from a char *? Or perhaps is there a better way to approach the problem I'm trying to solve here?

EDIT: I was requested to provide an example, which I didn't think about and apologise for not giving one in the first place. I did read the answer by @chqrlie before writing this. The following code gives a segmentation fault.

#define _GNU_SOURCE                                                                                                
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdbool.h>
#include <regex.h>

int main() {
  FILE * file = fopen("myfile", "r");
  char * line = NULL;
  size_t len = 0;
  ssize_t read;

  regex_t regex;
  const char * regexStr = "a+b*";

  if (regcomp(&regex, regexStr, 0)) {
    fprintf(stderr, "Could not compile regex \"%s\"\n", regexStr);
    exit(1);
  }

  while ((read = getline(&line, &len, file)) != -1) {
    int match = regexec(&regex, line, 0, NULL, 0);

    if (match == 0) {
      printf("%s matches\n", line);
    }
  }

  fclose(file);

  return 0;
}

Solution

  • char * can be converted to const char * without any special syntax. The const in this type means that the data pointed by the pointer will no be modified via this pointer.

    char array[] = "abcd";  // modifiable array of 5 bytes
    char *p = array;        // array can be modified via p
    const char *q = p;      // array cannot be modified via q
    

    Here are some examples:

    int strcmp(const char *s1, const char *s2);
    size_t strlen(const char *s);
    char *strcpy(char *dest, const char *src);
    

    As you can see, strcmp does not modify the strings it receives pointers to, but you can of course pass regular char * pointers to it.

    Similarly, strlen does not modify the string, and strcpy modifies the destination string but not the source string.

    EDIT: You problem has nothing to do with constness conversion:

    • You do not check the return value of fopen(), the program produces a segmentation fault on my system because myfile does not exist.

    • You must pass REG_EXTENDED to compile a regex with the newer syntax such asa+b*

    Here is a corrected version:

    #define _GNU_SOURCE
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <regex.h>
    
    int main() {
        FILE *file = fopen("myfile", "r");
        char *line = NULL;
        size_t len = 0;
        ssize_t read;
    
        regex_t regex;
        const char *regexStr = "a+b*";
    
        if (file == NULL) {
            printf("cannot open myfile, using stdin\n");
            file = stdin;
        }
    
        if (regcomp(&regex, regexStr, REG_EXTENDED)) {
            fprintf(stderr, "Could not compile regex \"%s\"\n", regexStr);
            exit(1);
        }
    
        while ((read = getline(&line, &len, file)) != -1) {
            int match = regexec(&regex, line, 0, NULL, 0);
            if (match == 0) {
                printf("%s matches\n", line);
            }
        }
    
        fclose(file);
        return 0;
    }