concatenate variable onto another variable - c

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.

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 ;
}

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;
}

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);

Related

Reducing number of required pointer variables in regex code

I finally managed to make my regex function work, but I want to know if I can possibly reduce the number of pointer declarations in the main function to one. For example, I want to convert:
int main(){
regex* r=calloc(1,300000);
regex* rr=r;
if (regexmatch("T/2/b","([A-Z]+)/([0-9]+)/([a-z]+)",10,&rr)==0){
printres(r);
}
free(r);
return 0;
}
to something like:
int main(){
regex* r=calloc(1,300000);
if (regexmatch("T/2/b","([A-Z]+)/([0-9]+)/([a-z]+)",10,&r)==0){
printres(r);
}
free(r);
return 0;
}
but as it stands, this won't work because the regexmatch function seems to change the address of the variable which causes the program to crash at free(r);
I even tried adding reg=rp; just before the last return statement in the function in hopes that I reset the struct variable address to what it was when the function was first called, but that didn't work.
What can I do to fix this? or is my only option to use two pointers in my main function?
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <regex.h>
typedef struct{
char str[1000];
} regex;
long regexmatch(const char* str,const char* regexs,const size_t nummatch,regex** rp){
regex** reg=rp;
regex_t r;regmatch_t match[nummatch];
if (regcomp(&r,regexs,REG_EXTENDED) != 0){return -1;}
if (regexec(&r,str,nummatch,match,0)!=0){regfree(&r);return -1;}
regfree(&r);size_t i=0;
for (i=0;i<nummatch;i++){
if (match[i].rm_so > -1){
unsigned long sz=match[i].rm_eo-match[i].rm_so;
if (sz > 0 && sz < 1000){
memcpy((**reg).str,(char*)(str+match[i].rm_so),sz);
(*reg)++;
}
}
}
(**reg).str[0]='\0';
return 0;
}
void printres(regex* r){
printf("Matches\n");
while (r->str[0] != '\0'){
printf("%s\n",r->str);
r++;
}
}
int main(){
regex* r=calloc(1,300000);
regex* rr=r;
if (regexmatch("T/2/b","([A-Z]+)/([0-9]+)/([a-z]+)",10,&rr)==0){
printres(r);
}
free(r);
return 0;
}
Why do you pass rp by reference? You clearly don't want the value in the calling program to change, so it would be simpler to just pass it directly.
In fact, what you really want that parameter to be is an array of regex objects ([Note 1]). So instead of using the prototype
long regexmatch(const char* str,
const char* regexs,
const size_t nummatch, /* This const is pointless */
regex** rp);
it would make more sense to use:
long regexmatch(const char* str,
const char* regexs,
size_t nummatch,
regex rp[nummatch]);
(Effectively, that's the same as using regex* rp as a parameter, but writing it as rp[nummatch] is more self-documenting. Because you use an empty string as a terminator (which means that you can't handle zero-length captures), you actually need nummatch to be at least one greater than the number of captures in the pattern, so it is not 100% self-documenting.
Having made that change to the prototype, you need to remove one level of indirection in the function:
long regexmatch(const char* str,
const char* regexs,
size_t nummatch,
regex reg[nummatch]){
/* Compiling the regex is the same as in your code. I removed
* the assignment of reg from rp, since the parameter is now
* called reg.
*/
size_t i=0;
for (i=0;i<nummatch;i++){
if (match[i].rm_so > -1){
unsigned long sz=match[i].rm_eo-match[i].rm_so;
if (sz > 0 && sz < 1000){
memcpy(reg->str, (char*)(str+match[i].rm_so), sz);
/* The above memcpy doesn't nul-terminate the string,
* so I added an explicit nul-termination.
*/
reg->str[sz] = 0;
/* I think this should be outside the if statement. Personally,
* I'd put it in the increment clause of the for loop.
* See Note 2.
*/
reg++;
}
}
}
reg->str[0] = 0;
return 0;
}
(See it live on ideone.)
Notes
I found it confusing to call regex what is basically a fixed-length string representing a regex capture. Also, I don't see the point of wrapping the fixed-length character allocation in a struct, unless you plan to assign to values of type regex. But all of that is irrelevant to your basic question.
When you're copying captures into your regex array, you simply ignore captures which are empty, unset, or too long. This means that you cannot access capture i by looking at the ith element in the array. If a previous capture happened to be empty, then the capture will be at position i - 1 (or earlier, if more than one capture were empty), and the empty capture won't be accessible at all. I'm not sure exactly what your goal here is, but that seems hard to use. However, since you use empty strings to indicate the end of the capture list, you cannot insert an empty capture into the list. So you really might want to rethink the API.
A much cleaner approach would be to use an array of pointers to strings (like argv.)
In regexmatch add : regex* rp2=*rp;regex** reg=&rp2;
In your code (*reg)++; is modifying the value of rp. Its equivalent of rp++ in your code because regex** reg=rp;
rp is the pointer adress to your calloc set by &r in regexmatch call.
You dont want to change this pointer. So we use another pointer called rp2.

Node v8 variable default NULL but reassign based on argument passed

I'm sure it's really basic but I haven't been able to find anything like it (perhaps I'm going about it completely the wrong way).. I'm trying to pass str to the 'call_to_c_lib_func' function which takes either NULL or a string (char*).
#include <stdio.h>
#include <string.h>
#include <v8.h>
void test(const v8::FunctionCallbackInfo<Value>& args) {
char *str = NULL;
if (!args[3]->IsNull() && !args[3]->IsUndefined()) {
String::Utf8Value arg_str(args[3]->ToString());
str = *arg_str;
}
// Following function takes either NULL or char*
call_to_c_lib_func(str);
}
Edit: Post originally contained simplified C code for this which didn't really help explain the problem, hopefully this clarifies it a bit.
Your post doesn't ask a question or explain what problem you are having with the code. So I am assuming you ran the code exactly as posted and sometimes the call to the function behaves oddly or crashes.
Your existing code fails because:
String::Utf8Value arg_str(args[3]->ToString());
is inside a { code block } but you try to access its contents after that code block has exited (and therefore after arg_str has been destroyed).
Instead you could write:
String::Utf8Value temp;
char *str = NULL;
if (!args[3]->IsNull() && !args[3]->IsUndefined())
{
temp = args[3]->ToString();
str = *temp;
}
call_to_c_lib_func( str );
Of course there are many ways to skin a cat, just watch out when using v8::String that you do not use the result of operator* after the string has been destroyed, because it returns a pointer to the content of the string.
NB. I'm not familiar with V8 so there may be a more elegant way of accessing args[3]'s string data that neither of us is aware of.

Appending element into an array of strings in C

I have an array of strings with a given size, without using any memory allocation, how do I append something into it?
Say I run the code, its waiting for something you want to enter, you enter "bond", how do I append this into an array ? A[10] ?
If the array declared like
char A[10];
then you can assign string "bond" to it the following way
#include <string.h>
//...
strcpy( A, "bond" );
If you want to append the array with some other string then you can write
#include <string.h>
//...
strcpy( A, "bond" );
strcat( A, " john" );
You can't append to an array. When you define the array variable, C asks the is for enough contiguous memory. That's all the memory you ever get. You can modify the elements of the array (A[10]=5) but not the size.
However, you CAN create data structures that allow appending. The two most common are linked lists and dynamic arrays. Note, these are no built into the language. You have to implement them yourself or use a library. The lists and arrays of Python, Ruby and JavaScript are implemented as dynamic arrays.
LearnCThHardWay has a pretty good tutorial on linked lists, though the one on dynamic arrays is a little rough.
Hi,
It really depends on what you mean by append.
...
int tab[5]; // Your tab, with given size
// Fill the tab, however suits you.
// You then realize at some point you needed more room in the array
tab[6] = 5; // You CAN'T do that, obviously. Memory is not allocated.
The problem here can be two things :
Did you misjudge the size you need ? In that case, just make sure this given size you mentioned is correctly 'given', however that might be.
Or don't you know how much room you want at the beginning ? In that case, you''ll have to allocate the memory yourself ! There is no other way you can resize a memory chunk on the fly, if I might say.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STR_MAX_SIZE 255 // Maximum size for a string. Completely arbitray.
char *new_string(char *str)
{
char *ret; // The future new string;
ret = (char *) malloc(sizeof(char) * 255); // Allocate the string
strcpy(ret, str); // Function from the C string.h standard library
return (ret);
}
int main()
{
char *strings[STR_MAX_SIZE]; // Your array
char in[255]; // The current buffer
int i = 0, j = 0; // iterators
while (in[0] != 'q')
{
printf("Hi ! Enter smth :\n");
scanf("%s", in);
strings[i] = new_string(in); // Creation of the new string, with call to malloc
i++;
}
for ( ; j < i ; j++)
{
printf("Tab[ %d ] :\t%s\n", j, strings[j]); // Display
free(strings[j]); // Memory released. Important, your program
// should free every bit it malloc's before exiting
}
return (0);
}
This is the easiest solution I could think of. It's probably not the best, but I just wanted to show you the whole process. I could have used the C standard library strdup(char *str) function to create a new string, and could have implemented my own quick list or array.
The size of an array variable cannot change. The only way to append to an array is to use memory allocation. You are looking for the realloc() function.
If you want to append a character or string to it;
strcpy(a, "james")
strcpy(a, "bond")

How to make a pointer in a function change the pointee in C

Hee guys,
I have been reading a couple of things about pointers and pointees and started getting curious. The only thing I dont understand is how pointers behave in functions, hence the following code:
#include <stdio.h>
int pointeeChanger(char* writeLocation) {
writeLocation = "something";
return 0;
}
int main(void)
{
char crypted[] = "nothing";
char* cryptedPointer = crypted;
pointeeChanger(cryptedPointer);
printf("The new value is: %s", cryptedPointer);
return 0;
}
What my intention to do is to adjust the pointee, "crypted" var, through a pointer given to a function. The only thing is that it is not working. Could you please explain me what is going wrong in my thought process. I am fairly new to C so my errors could be fairly basic.
Thanks in advance!
Greetings,
Kipt Scriddy
C strings are not the best material to learn pointers, because they are implemented as pointers to char. Let's use int instead:
#include <stdio.h>
void pointeeChanger(int* writeLocation) {
// Using dereference operator "*"
*writeLocation = 42; // something
}
int main(void) {
int crypted = 0; // Nothing
pointeeChanger(&cryptedPointer); // Taking an address with "&"
printf("The new value is: %d", crypted);
return 0;
}
This works as expected.
Modifying strings in place is a lot harder, because you are forced to deal with memory management issues. Specifically, the string into which you copy must have enough space allocated to fit the new string. This wouldn't work with "nothing" and "something", because the replacement is longer by two characters.
Short answer: writeLocation is a local variable and is a copy of cryptedPointer. When you modify writeLocation, cryptedPointer is not modified.
If you want to modify cryptedPointer, you have to pass a pointer to it, like so:
#include <stdio.h>
int pointeeChanger(char** writeLocation) { /* Note: char** */
*writeLocation = "something"; /* Note: *writeLocation */
return 0;
}
int main(void)
{
char crypted[] = "nothing";
char* cryptedPointer = crypted;
pointeeChanger(&cryptedPointer); /* Note: &cryptedPointer */
printf("The new value is: %s", cryptedPointer);
return 0;
}
There are other issues with this code though. After the call to pointeeChanger(), cryptedPointer no longer points to the crypted array. I suspect you actually wanted to change the contents of that array. This code fails to do that.
To change the value of crypted[] you will need to use strcpy() or (preferably) strncpy(). Also you will need to watch the size of the crypted[] array - "something" is longer than "nothing" and will cause a buffer overflow unless crypted[] is made larger.
This code will modify the original crypted[] array:
#include <stdio.h>
#include <string.h>
#define MAX_STR_LEN 64
/*
* Only char* required because we are not modifying the
* original pointer passed in - we are modifying what it
* points to.
*/
int pointeeChanger(char* writeLocation)
{
/*
* In C, you need to use a function like strcpy or strncpy to overwrite a
* string with another string. Prefer strncpy because it allows you to
* specify a maximum size to copy, which helps to prevent buffer overruns.
*/
strncpy(writeLocation, "something", MAX_STR_LEN);
/* strncpy doesn't automatically add a \0 */
writeLocation[MAX_STR_LEN] = '\0';
return 0;
}
int main(void)
{
/*
* The +1 is because an extra character is required for the
* null terminator ('\0')
*/
char crypted[MAX_STR_LEN + 1] = "nothing";
pointeeChanger(crypted);
printf("The new value is: %s", crypted);
return 0;
}
It depends slightly on what you actually want to do:
Do you want to change what cryptedPointer is pointing to, or change the content that cryptedPointer is pointing at?
The second can be done by:
strcpy(writeLocation, "something");
Beware that if something is longer than what the original string's size, you'll overflow the buffer, which is a bad thing. So to fix this, you'd have to have char crypted[10] = "nothing";, to make space for the string "something".
You can clearly also do something like:
writeLocation[2] = 'f';
writeLocation[3] = 'f';
and have the printf print "noffing"
but if you want to do the first variant, then you need to pass a pointer to the pointer:
int pointeeChanger(char** writeLocation) {
*writeLocation = "something";
return 0;
}
And then call:
pointeeChanger(&cryptedPointer);
Note that when this returns, cruptedPointer is pointing at a constant string that can't be modified, where your original crypted can be modified.
Consider that Tom is hired by Sally to break knuckles for the mafia.
Pass-by-value: If Sally tells Tom to count the number of knuckles he breaks at work today, then Sally has no way of knowing which number Tom has come up with until he returns from the road. They both have a copy of the number "zero" in their heads to begin with, but Tom's number might increase throughout the course of the day.
Note the word "copy". When you pass-by-value to a function, you're passing a copy of the object. When you modify the object within a function, you're modifying the copy instead of the original.
Pass-by-reference: If Sally tells Tom to tally the number of knuckles he breaks in the sky, then she (and anyone else who's interested) can refer to the sky. By changing the sky, Tom would also be changing Sally's number.
edit: C doesn't have pass-by-reference, though it does have pointers, which are reference types. Passing a pointer is still pass-by-value, and a copy with the same pointer value is still formed. Hence, your assignment is to the copy, not the original.

Assign a string created in a function to a typedef structure array created in main

Alright. So I have this program in C where I take a string with arguments and values (Such as: "GO 45 STOP 15"). The goal is to parse the string and place the argument with its corresponding value into a typedef structure to work with later on.
This is what my structure looks like:
typedef struct {
char* keyword;
double value;
} parameter;
Here are some copies of my code that I am having issues with.
Both main() and initParams() are in the same file and therefore both have access to the same #defines...
main():
#include <stdio.h>
#include <stdlib.h>
#include "findArgs.h"
#define STR0_SIZE 80
#define LIST_SIZE 4
#define MAX_PARAMS 15
void main(){
int i;
char str0[STR0_SIZE] = "LEFT 45 GO 686 GO 34.3 STOP 56 RIGHT 26"; //Input String
char* wordList[LIST_SIZE]={"GO", "STOP", "LEFT", "RIGHT"};
int num_arg = 0; //Number of arguements in str0 (each space denotes the end of an arg)
parameter* param;
initParams(param);
replaceSpaces(str0, &num_arg);
findWords(param, str0, num_arg);
}
initParams:
void initParams(parameter* param){
int ctr0, ctr1;
param = (parameter*) malloc(MAX_PARAMS * sizeof(parameter));
printf("\n%i\n", sizeof(parameter));
for(ctr0=0;ctr0<MAX_PARAMS;ctr0++){
param[ctr0].keyword = "";
param[ctr0].value = 0;
}
}
ok some quick explainations. initParams is for allocating the memory for each of my parameters. I am assuming that I will not have any idea how many parameters will be included in the string and plan on determining the number in the string later in the program. I do know that I will not accept more than parameters in the string.
After allocating the memory, I loop through each one and initialize each value to either an empty string or 0. (I do realize this is probably unnecessary, however I have done this as part of my code troubleshooting.
Continuing on, replaceSpaces() simply loops through the string and replaces each occurrence of ' ' with a '\0'. It also counts the number of arguements present in the string so that I know how many new strings I have just created by adding null terminators.
Now the tricky part in which I am having difficulty.
#define MAX_ARG_LENGTH 20
void findWords(parameter* param, char* str0, int num_arg){
parameter temp[countWords(str0, num_arg)];
int i;
int ctr0,ctr1, ctr2=0;
int word=0; //flag
char tempStr[MAX_ARG_LENGTH]="";
char* c0 = str0;
for(ctr0=0; ctr0<num_arg; ctr0++){
word=0;
ctr1=0;
if(((*c0 > 'a') && (*c0 <'z')) || ((*c0 > 'A') && (*c0 <'Z'))){
word=1;
tempStr[ctr1]=*c0;
ctr1++;
}
while(*c0 != '\0'){
c0++;
if(word)
tempStr[ctr1++] = *c0;
printf("\ntempStr: '%s'\n", tempStr);
}
if(word){
param[ctr2].keyword = tempStr;
printf("%s\n", param[ctr2].keyword);
ctr2++;
}
c0++;
}
for(i=0; i<num_arg/2;i++){
printf("'%s'\n", param[i].keyword);
printf("'%g'\n", param[i].value);
}
}
This function works properly at finding each word in the string and storing it in tempStr. My issue is with assigning it to my parameter array back in my main(). I have tried assigning them to a temp array of parameters and then setting "param" equal to the temp array. However due to the fact that param is a pointer, when I assign it a local location, after the function is finished, the memory is freed and lost. Enter my idea to use malloc to predefine memory for them and assign it after.
This is my current output when I compile and run the code. I added comments to clarify
16 //sizeof(parameter)
5 //Number of words in str0
LEFT
GO
GO
STOP
RIGHT
'RIGHT' //Things in single quotes are prints from the array of parameters
'8.05316e-315'
'RIGHT'
'0'
'RIGHT'
'8.04051e-315'
'RIGHT'
'0'
'RIGHT'
'0'
MAIN: //I printed these in main using the same for loop seen in findWord()
'▒▒'
'8.05316e-315'
'▒▒'
'0'
'▒▒'
'8.04051e-315'
'▒▒'
'0'
'▒▒'
'0'
If anyone can help me properly assign the contents of tempStr to a parameter in my array declared in main I would be greatly appreciative. Please Let me know if you need any more information.
THANK YOU ALL!! I GOT IT!!!
Rather than make "tempStr" I just assgned the characters directly to the param[index].keyword. It worked like a charm
Thank you guys very much! I had read many different Qs and As here before but this was my first time posting. I am very excited with how quickly you guys were able to reply.
Thanks again!
~Nick
I think you are misunderstanding what param[ctr2].keyword = tempStr; does It does not copy the string in tempstr to keyword it just makes keyword point to tempstr, which means all the keywords will point to the tempStr variable and will be invalid if you access it outside this function.
What you want to do is to make
char* keyword;
into
char keyword[MAX_ARG_LENGTH];
And use something like strcpy or strncpy to do the copying.
You also do not appear to be setting value anywhere

Resources