2
const char *SITE_NAME = "test";
char SITE_ROOT[19];
sprintf (SITE_ROOT, "/var/www/html/%s", SITE_NAME);

I can't figure out why I'm getting an error of:

error: expected ‘)’ before string constant

Basically I just want to concatenate the variable SITE_NAME onto SITE_ROOT. The error is on the sprintf line. Any ideas?

UPDATE: So the code works if it is inside main(). I had it outside of main() so that I could use those variables inside of functions.

8
  • Which line is giving you the error? Commented May 26, 2013 at 2:57
  • @JackManey - I have updated my post...the error is on the sprintf line. Commented May 26, 2013 at 2:59
  • An unexpected macro may be messing things up. Check the preprocessor output. (cc -E file.c for unix-like compilers; tell what compiler you're using if you need more help) Commented May 26, 2013 at 3:17
  • You wrote: "I had it outside of main()"... that's not how C works. Commented May 26, 2013 at 3:51
  • Note that you can still keep the variables outside of any function and use them globally, it's the sprintf call that's the problem. I'm curious, though, as to why you're trying to do it this way instead of const char SITE_ROOT[] = "/var/www/html/test";. What exactly are you trying to accomplish by splitting it up and immediately doing the concatenation? Commented May 26, 2013 at 12:21

3 Answers 3

4

The error looks like it might not be shown in the code but the sprintf should be:

sprintf (SITE_ROOT, "/var/www/html/%s", SITE_NAME);

EDIT:

Here is my complete test code if that helps at all:

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

int main()
{
    const char *SITE_NAME = "test";
    char SITE_ROOT[19];
    sprintf (SITE_ROOT, "/var/www/html/%s", SITE_NAME);

    printf( "%s\n", SITE_ROOT ) ;

    return 0 ;
}
Sign up to request clarification or add additional context in comments.

5 Comments

I have taken off the ampersand in front of SITE_NAME and it is still giving an error. I added the ampersand because I thought SITE_NAME is defined as a pointer and to call that pointer I need to put an ampersand, no?
@user983223 It is odd, I cannot reproduce that error at all. The %s format specifier expect a c style string which is a char * which is what SITE_NAME is. I will update my post with my complete test code in case that helps.
@Shafik_Yaghmour - That standalone code works. I'll divide and conquer and try and figure out what function is not liking it.
@ShafikYaghmour - The code works because the variables are defined inside of main(). I hade them outside of main() so that the variables would be available to other functions.
@user983223 Ah, ok, that makes more sense. You can have global variables but you can not have statements like sprintf outside of main of a function.
2

As has been pointed out, the direct problem is that you're trying to call sprintf from outside a function.

You mentioned that you are setting the strings this way because you're using SITE_NAME by itself in addition to concatenating it with the path and you want to only have to change it in one place. This is a good goal, known in some circles as "don't repeat yourself" (often abbreviated DRY). However, even if the code worked (say, because you moved the sprintf call into main), you haven't really achieved your goal due to the following line:

char SITE_ROOT[19];

You are declaring a fixed length array exactly big enough to hold "/var/www/html/test", which is just asking for a buffer overflow. When you change SITE_NAME from "test" to, for example, "someRealSiteName", you'll very probably overwrite something else when you concatenate, causing unpredictable results. So you have to manually recalculate the length of the final string and update the array size (which would be easy to get wrong, say by forgetting to add 1 for the null terminator) every time you change SITE_NAME.

You could, of course, limit the length of SITE_NAME and size SITE_ROOT to hold the longest possible path, but it'd be an artificial limit and you might end up wasting space. Furthermore, you'd still have to verify the length isn't exceeded at run-time (or use a function that will ignore extra characters).

Instead, you could dynamically set the size of SITE_ROOT like so:

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

const char SITE_PATH[] = "/var/www/html/";
const char SITE_NAME[] = "someRealSiteName";
char *SITE_ROOT = NULL; // just making this explicit, would be set to 0 anyway

int main(void)
{
    size_t siteRootLength = strlen(SITE_PATH) + strlen(SITE_NAME);

    SITE_ROOT = malloc(siteRootLength + 1); //don't forget to account for the terminating '\0'

    strcpy(SITE_ROOT, SITE_PATH);
    strcat(SITE_ROOT, SITE_NAME);

    printf("%s\n", SITE_NAME):
    printf("%s\n", SITE_PATH):
    printf("%s\n", SITE_ROOT):

    return 0;
}

This solution is okay, but has some drawbacks:

  • SITE_ROOT can't be a const pointer , so both the string and the pointer itself could be accidentally changed
  • Site path and name will each be in memory twice (though it sounds like you're okay with that)
  • Concatenation is being done at run-time when it could be done at compile-time
  • Code is longer and more complex than necessary for such a simple task
  • Risk that SITE_ROOT is used before it has the correct value (or is even a valid pointer/string!) in some other initialization code or another thread.

I feel something like the following is better:

#include <stdio.h>

#define SITE_PATH_MACRO "/var/www/html/"
#define SITE_NAME_MACRO "someRealSiteName"

// the preprocessor will merge the two string literals into one
#define SITE_ROOT_MACRO SITE_PATH_MACRO SITE_NAME_MACRO

// you could do without some or all of these if you don't need them
// (or are willing to use the macros directly)
const char SITE_PATH[] = SITE_PATH_MACRO;
const char SITE_NAME[] = SITE_NAME_MACRO;
const char SITE_ROOT[] = SITE_ROOT_MACRO;

int main(void)
{
    printf("%s\n", SITE_NAME);
    printf("%s\n", SITE_PATH);
    printf("%s\n", SITE_ROOT);

    return 0;
}

1 Comment

@user983223 I'm glad you found it helpful. I should point out that the merging of string literals doesn't only work in conjunction with macros, it just happens to be most useful there. So you could do const char SITE_ROOT[] = SITE_PATH_MACRO SITE_NAME_MACRO to get rid of one macro or const char SITE_ROOT[] = "/var/www/html/" SITE_NAME_MACRO to get rid of two (if you didn't need the SITE_PATH variable)
1

Since this is a pretty straightforward case, you can simply initialize the string and then concatenate onto it. You might want to add checks to ensure you don't go beyond you string's boundaries though.

strcpy(SITE_ROOT, "/var/www/html/"); 
strcat(SITE_ROOT, SITE_NAME);

1 Comment

If you're going to keep SITE_ROOT as a fixed length buffer (which it seems you're implying), you can directly initialize it with char SITE_ROOT[19] = "/var/www/html/" and skip the strcpy call.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.