I have a string "Revision: BG96MAR02A07M1G" which is stored in char tempdata[512]
I'm trying to parse and copy only that part BG96MAR02A07M1G
this what I did, but I get garbage values in firmwareVersion
signed char updateBG96FirmwareVersion(int timeout)
{
char firmwareVersion[24];
char *ret = NULL;
if (GSMCommand("I", tempdata, timeout) != AT_OK)
return FEHLER;
ret = strstr(tempdata, "Revision:");
if (ret)
{
strncpy(firmwareVersion, tempdata+9, 24);
firmwareVersion[sizeof(firmwareVersion)] = '\0';
}
else
return FEHLER;
}
test
You can just do this:
#include <string.h>
#define FEHLER 123 // ?
#define SUCCESS 0
signed char updateBG96FirmwareVersion(int timeout)
{
char firmwareVersion[24];
char* ret = NULL;
#if 1
char tempdata[] = "Revision: BG96MAR02A07M1G"; // Test data for my test
#else
if (GSMCommand("I", tempdata, timeout) != AT_OK)
return FEHLER;
#endif
const char revision[] = "Revision: ";
ret = strstr(tempdata, revision);
if (ret)
{
strcpy(firmwareVersion, tempdata + strlen(revision));
return SUCCESS;
}
else
return FEHLER;
}
int main() // main function initializing here
{
updateBG96FirmwareVersion(0);
}
This assumes that the revision string BG96MAR02A07M1G is never longer than 24 characters. Otherways you probably should use strncpy and terminate the string with a 0 manually.
Related
I am a newbie in C. I am trying to build a whitelist program that returns 0 if a character in the given string (user_data) is not in the list of 'ok_chars'
#include <stdio.h>
#include <string.h>
static char ok_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890.";
char user_data[] = "Bad &";
char * cp = user_data;
const char * end = user_data + strlen (user_data);
for (cp += strspn(cp , ok_chars); cp != end; cp += strspn (cp , ok_chars)) {
//*cp = '_';
if(user_data not in ok_chars){ //I don't know how to implement this
return 0;
}
}
Kindly assist.
int isOK(const char *needles, const char *haystack)
{
int result = 1;
while(*needles)
if(!strchr(haystack, *needles++))
{
result = 0;
break;
}
return result;
}
/* .... */
if(!isOK(user_data, ok_chars))
return 0;
/* .... */
i'm trying to add an extension to a c-string, but i just get Signal: SIGABRT (Aborted), can anyone tell me what's the reason for this? This is what i've done so far, the error comes # realloc in function "prepareFileName":
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define OUT_OF_MEMORY 3
#define FILE_EXTENSION ".txt"
typedef enum _Bool_ // enum _Bool_ is a non-typedef'ed enum
{
FALSE = 0, // Enum element
TRUE = 1 // Enum element
} Bool; // Bool is the typedef'ed enum
Bool cStringEndsWith(const char *sourceString, const char *suffix) {
if (!sourceString || !suffix) // Check for not null pointer
{
return FALSE;
}
size_t length_of_c_string = strlen(sourceString);
size_t length_of_suffix = strlen(suffix);
if (length_of_suffix > length_of_c_string) {
return FALSE;
}
int compare_result = strncmp(sourceString + length_of_c_string - length_of_suffix, suffix, length_of_suffix);
if (compare_result == 0) {
return TRUE;
} else {
return FALSE;
}
}
int prepareFileName(char **ptr_file_name){
int ends_with_file_extension = cStringEndsWith(*ptr_file_name, FILE_EXTENSION);
if(!ends_with_file_extension)
{
char *new_ptr_file_name = realloc(*ptr_file_name, strlen(*ptr_file_name) + strlen(FILE_EXTENSION) + 1);
if(!new_ptr_file_name)
return OUT_OF_MEMORY;
*ptr_file_name = new_ptr_file_name;
strcat(*ptr_file_name, FILE_EXTENSION);
}
}
int main()
{
char *file_name = "testFileName";
printf("Filename unprepared: \"%s\"", file_name);
prepareFileName(&file_name);
printf("Filename prepared: \"%s\"", file_name);
return 0;
}
file_name is in the text segment (read only) of your program. Use malloc() + strcpy() to allocate the space on the heap.
See man realloc
Unless ptr is NULL, it must have been returned by an earlier call to
malloc(), calloc() or realloc().
I am trying to make a suid application that will only execute ruby scripts located in a restricted folder. I have tried to do this using realpath(3) but it is only returning the first segment of the path. Below is my code...
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#define SUEXEC_STR_LEN 2048
#define RUBY_APP "/usr/bin/ruby"
#define DIRECTORY_SEPARATOR "/"
static void safepath(const char *path_in, char * path_out, int outlen) {
realpath(path_in, path_out);
}
int main ( int argc, char *argv[] )
{
char cmd[SUEXEC_STR_LEN];
char path_out[SUEXEC_STR_LEN];
char path_in[SUEXEC_STR_LEN];
char *cp = &cmd[0];
strncpy(cp, RUBY_APP, SUEXEC_STR_LEN - 1);
strncpy(path_in, DIRECTORY_SEPARATOR, SUEXEC_STR_LEN - 1);
strncat(path_in,argv[1],SUEXEC_STR_LEN - 1);
safepath(path_in,path_out,SUEXEC_STR_LEN - 1);
printf("path_in=%s path_out=%s\n",path_in,path_out);
setuid( 0 );
// system( cmd );
return 0;
}
This is an example of the result I'm getting
root#server01:/root/src# ./a.out foo/bar/../test
path_in=/foo/bar/../test path_out=/foo
This is the result I want
root#server01:/root/src# ./a.out foo/bar/../test
path_in=/foo/bar/../test path_out=/foo/test
You should check for realpath()'s return value. As described in its man page,
RETURN VALUE
If there is no error, realpath() returns a pointer to the resolved_path.
Otherwise it returns a NULL pointer, and the contents of the array resolved_path are undefined. The global variable errno is set to indicate the error.
Also in ERRORS section of its man page,
ENOENT The named file does not exist.
Thus, if there is indeed no /foo/test in your file system, realpath() should return NULL and the output is undefined.
So, here's a working sketch of how you might go about it in C on Linux. This is a quick hack that I do not represent as being exemplary code, efficient, etc. It (ab)uses PATH_MAX, uses “bad” string functions, and may leak memory, eat your cat, and have corner cases that segfault, etc. When it breaks, you get to keep both parts.
The basic idea is to go through the given path, breaking it up into “words” using “/” as the delimiter. Then, go through the list, pushing the “words” onto a stack, but ignoring if empty or “.”, and popping if “..”, then serializing the stack by starting at the bottom and accumulating a string with slashes in between.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <linux/limits.h>
typedef struct stack_s {
char *data[PATH_MAX];
int top;
} stack_s;
void stack_push(stack_s *s, char *c) {
s->data[s->top++] = c;
}
char *stack_pop(stack_s *s) {
if( s->top <= 0 ) {
return NULL;
}
s->top--;
return s->data[s->top];
}
// DANGER! DANGER! Returns malloc()ed pointer that you must free()
char *stack_serialize(stack_s *s) {
int i;
char *buf;
int len=1;
for(i=0; i<s->top; i++) {
len += strlen(s->data[i]);
len++; // For a slash
}
buf = malloc(len);
*buf = '\0';
for(i=0; i<s->top-1; i++) {
strcat(buf, s->data[i]);
strcat(buf, "/");
}
strcat(buf, s->data[i]);
return buf;
}
// DANGER! DANGER! Returns malloc()ed pointer that you must free()
char *semicanonicalize(char *src) {
char *word[PATH_MAX] = {NULL};
int w=0;
int n_words;
char *buf;
int len;
char *p, *q;
stack_s dir_stack = {{NULL},0};
// Make a copy of the input string:
len = strlen(src);
buf = strdup(src);
// Replace slashes with NULs and record the start of each "word"
q = buf+len;
word[0]=buf;
for(p=buf,w=0; p<q; p++) {
if(*p=='/') {
*p = '\0';
word[++w] = p+1;
}
}
n_words=w+1;
// We push w[0] unconditionally to preserve slashes and dots at the
// start of the source path:
stack_push(&dir_stack, word[0]);
for(w=1; w<n_words; w++) {
len = strlen(word[w]);
if( len == 0 ) {
// Must've hit a double slash
continue;
}
if( *word[w] == '.' ) {
if( len == 1 ) {
// Must've hit a dot
continue;
}
if( len == 2 && *(word[w]+1)=='.' ) {
// Must've hit a '..'
(void)stack_pop(&dir_stack);
continue;
}
}
// If we get to here, the current "word" isn't "", ".", or "..", so
// we push it on the stack:
stack_push(&dir_stack, word[w]);
}
p = stack_serialize(&dir_stack);
free(buf);
return p;
}
int main(void)
{
char *in[] = { "/home/emmet/../foo//./bar/quux/../.",
"../home/emmet/../foo//./bar/quux/../.",
"./home/emmet/../foo//./bar/quux/../.",
"home/emmet/../foo//./bar/quux/../."
};
char *out;
for(int i=0; i<4; i++) {
out = semicanonicalize(in[i]);
printf("%s \t->\t %s\n", in[i], out);
free(out);
}
return 0;
}
This is the code which I used as a solution to the problem. It may have some bugs remaining in it, and it isn't checking the outlen argument to avoid segfaults and other uglyness but it seems to get the job done.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <linux/limits.h>
#define SUEXEC_STR_LEN 2048
#define RUBY_APP "/usr/bin/ruby"
#define DIRECTORY_SEPARATOR "/"
#define RUBY_EXT ".rb"
#define SERVICES_BASE_PATH "/path/to/ruby/services"
static inline int isDirSeparator(const char c) { return (c == '/' || c == '\\'); }
static void safepath(const char *path_in, char * path_out, int outlen)
{
char *dirs[PATH_MAX];
int depth = 0;
char *dstptr = path_out;
const char *srcptr = path_in;
*dstptr++ = DIRECTORY_SEPARATOR[0];
dirs[0] = dstptr;
dirs[1] = NULL;
depth++;
while (1) {
if ((srcptr[0] == '.') && isDirSeparator(srcptr[1])) {
srcptr += 2;
} else if (srcptr[0] == '.' && srcptr[1] == '.' && isDirSeparator(srcptr[2])) {
if (depth > 1) {
dirs[depth] = NULL;
depth--;
dstptr = dirs[depth-1];
} else {
dstptr = dirs[0];
}
srcptr += 3;
} else if (srcptr[0] == '.' && srcptr[1] == '.' && srcptr[2] == 0) {
if (depth == 1) {
srcptr += 2;
} else {
depth--;
dstptr = dirs[depth-1];
srcptr += 2;
}
} else {
while (!isDirSeparator(srcptr[0]) && srcptr[0]) {
*dstptr++ = *srcptr++;
}
if (srcptr[0] == 0) {
if (dstptr != dirs[0] && isDirSeparator(dstptr[-1])) {
dstptr[-1] = 0;
}
dstptr[0] = 0;
return;
} else if (isDirSeparator(srcptr[0])) {
if (dstptr == dirs[0]) {
srcptr++;
} else {
*dstptr++ = *srcptr++;
dirs[depth] = dstptr;
depth++;
}
while (isDirSeparator(srcptr[0]) && srcptr[0]) {
srcptr++;
}
} else {
path_out[0] = 0;
return;
}
}
}
}
int main ( int argc, char *argv[] )
{
int ret;
char cmd[SUEXEC_STR_LEN];
char path_out[SUEXEC_STR_LEN];
char path_in[SUEXEC_STR_LEN];
char *cp = &cmd[0];
if (argc < 2) {
fprintf(stderr,"usage: %s <service>\n",argv[0]);
return 1;
}
strncpy(cp, RUBY_APP, SUEXEC_STR_LEN - 1);
strncpy(path_in, DIRECTORY_SEPARATOR, SUEXEC_STR_LEN - 1);
strncat(path_in,argv[1],SUEXEC_STR_LEN - 1);
safepath(path_in,path_out,SUEXEC_STR_LEN - 1);
//printf("path_in=%s path_out=%s\n",path_in,path_out);
strncat(cmd," ",SUEXEC_STR_LEN - (1+sizeof(RUBY_EXT)));
strncat(cmd,SERVICES_BASE_PATH,SUEXEC_STR_LEN - (1+sizeof(RUBY_EXT)));
strncat(cmd,path_out,SUEXEC_STR_LEN - (1+sizeof(RUBY_EXT)));
strncat(cmd,RUBY_EXT,SUEXEC_STR_LEN - 1);
setuid( 0 );
ret = system( cmd );
if (ret == -1) {
return ret;
}
ret = WEXITSTATUS(ret);
return ret;
}
I am trying to use atof() to convert a string to a double (obviously), but the results are not what I expect. Here is the code and debug information about the variable values BEFORE atof():
d = atof (arg);
next.db = d;
*debug info*
arg = 0x0034f7b0 "10.0"
d = 0.0000000000000000
Once the program has stepped through atof(). the results are as follows:
arg = 0x0034f7b0 "ôþSÄ÷4"
d = 0.0000000000000000
As you can see, before the command, the arg variable does hold a valid double. Though, the return value is 0. What confuses me, is why does the value of arg change?
Also, I do have stdlib.h included. As well, arg is declared as:
char *arg;
If it helps at all, the "10.0" was read from a file.
More code:
void read_instructions()
{
char *str;
char *arg;
int n;
char c;
double d = 0;
instruction next = {0};
while (!feof(datafile)) {
// Fetch the next string
// if (push or pop), get the next argument
// create instructiwn and add to instruction array
str = get_next_string();
if (strncmp (str, "P", 1) == 0) {
if (strncmp (str, "PUSH", 4) == 0) {
next.func = pushFunc;
}
else {
next.func = popFunc;
}
arg = get_next_string();
n = arg[0];
if (n > 64 && n < 71)
next.ch = arg[0];
else {
d = atof (arg);
next.db = d;
}
instr[instr_count] = next;
instr_count++;
}
else {
c = str[0];
switch (c) {
case 'A' :
next.func = addFunc;
break;
case 'S' :
next.func = subFunc;
break;
case 'M' :
next.func = multFunc;
break;
case 'D' :
next.func = divFunc;
break;
case 'H' :
next.func = haltFunc;
default :
printf ("Invalid instruction");
}
instr[instr_count] = next;
instr_count++;
}
}
fclose (datafile);
}
This is the given code to open and access the file:
FILE *datafile;
int main(int argc, char *argv[])
{
if (argc != 2) {
printf("error, incorrect number of arguments");
haltFunc(instr[0]);
}
open_file(argv[1]);
read_instructions();
execute_instructions();
return 0;
}
void open_file(char* argv)
{
char buf[1024];
char cwd[512];
getcwd(cwd, sizeof cwd);
sprintf(buf, "%s\\%s", cwd, argv);
if (!(datafile = fopen(buf, "r"))) {
printf("Error: Make sure your file is located here:\n%s", buf);
}
}
char* get_next_string()
{
char str[15];
fscanf(datafile, "%s", &str);
return str;
}
The header file:
#ifndef MAIN_HEADER_H
#define MAIN_HEADER_H
#define INSTR_SIZE 30
typedef struct {
void (*func)(instruction);
union {
double db;
char ch;
};
} instruction;
int main(int, char*);
char* get_next_string();
void open_file(char*);
void read_instructions();
void execute_instructions();
void pushFunc(instruction instr);
void popFunc(instruction instr);
void addFunc(instruction instr);
void subFunc(instruction instr);
void multFunc(instruction instr);
void divFunc(instruction instr);
void haltFunc(instruction instr);
#endif
And this is the test file:
PUSH 10.0
PUSH 4.0
PUSH 7.0
PUSH 5.0
POP D
POP E
POP
PUSH D
ADD
PUSH 5.0
POP B
PUSH 17.0
POP E
PUSH B
PUSH E
SUB
HALT
Your problem is probably caused by the get_next_string() function returning a pointer to a temporary local character array. As soon as the function returns, the stack memory once used by str[] is being overwritten by some other automatic variable. That would explain why arg is being corrupted.
There are several possible fixes.
The caller could allocate memory to hold the string and pass this pointer to the function for it to fill with data.
The callee could allocate memory for the string and return that pointer. That also returns ownership to the caller and responsibility for calling free() when done.
The str[] array could be declared static inside the function. It would no longer be temporary but be aware that every time you call the function the previous string will be overwritten.
Finding some text and replacing it with new text within a C string can be a little trickier than expected.
I am searching for an algorithm which is fast, and that has a small time complexity.
What should I use?
I couldn't find an implementation of search/replace in C that I liked so I present here my own. It does not use things like strstr(), snprintf(), arbitrary length temporary buffers, etc. It only requires that the haystack buffer is large enough to hold the resulting string after replacements are made.
// str_replace(haystack, haystacksize, oldneedle, newneedle) --
// Search haystack and replace all occurences of oldneedle with newneedle.
// Resulting haystack contains no more than haystacksize characters (including the '\0').
// If haystacksize is too small to make the replacements, do not modify haystack at all.
//
// RETURN VALUES
// str_replace() returns haystack on success and NULL on failure.
// Failure means there was not enough room to replace all occurences of oldneedle.
// Success is returned otherwise, even if no replacement is made.
char *str_replace(char *haystack, size_t haystacksize,
const char *oldneedle, const char *newneedle);
// ------------------------------------------------------------------
// Implementation of function
// ------------------------------------------------------------------
#define SUCCESS (char *)haystack
#define FAILURE (void *)NULL
static bool
locate_forward(char **needle_ptr, char *read_ptr,
const char *needle, const char *needle_last);
static bool
locate_backward(char **needle_ptr, char *read_ptr,
const char *needle, const char *needle_last);
char *str_replace(char *haystack, size_t haystacksize,
const char *oldneedle, const char *newneedle)
{
size_t oldneedle_len = strlen(oldneedle);
size_t newneedle_len = strlen(newneedle);
char *oldneedle_ptr; // locates occurences of oldneedle
char *read_ptr; // where to read in the haystack
char *write_ptr; // where to write in the haystack
const char *oldneedle_last = // the last character in oldneedle
oldneedle +
oldneedle_len - 1;
// Case 0: oldneedle is empty
if (oldneedle_len == 0)
return SUCCESS; // nothing to do; define as success
// Case 1: newneedle is not longer than oldneedle
if (newneedle_len <= oldneedle_len) {
// Pass 1: Perform copy/replace using read_ptr and write_ptr
for (oldneedle_ptr = (char *)oldneedle,
read_ptr = haystack, write_ptr = haystack;
*read_ptr != '\0';
read_ptr++, write_ptr++)
{
*write_ptr = *read_ptr;
bool found = locate_forward(&oldneedle_ptr, read_ptr,
oldneedle, oldneedle_last);
if (found) {
// then perform update
write_ptr -= oldneedle_len;
memcpy(write_ptr+1, newneedle, newneedle_len);
write_ptr += newneedle_len;
}
}
*write_ptr = '\0';
return SUCCESS;
}
// Case 2: newneedle is longer than oldneedle
else {
size_t diff_len = // the amount of extra space needed
newneedle_len - // to replace oldneedle with newneedle
oldneedle_len; // in the expanded haystack
// Pass 1: Perform forward scan, updating write_ptr along the way
for (oldneedle_ptr = (char *)oldneedle,
read_ptr = haystack, write_ptr = haystack;
*read_ptr != '\0';
read_ptr++, write_ptr++)
{
bool found = locate_forward(&oldneedle_ptr, read_ptr,
oldneedle, oldneedle_last);
if (found) {
// then advance write_ptr
write_ptr += diff_len;
}
if (write_ptr >= haystack+haystacksize)
return FAILURE; // no more room in haystack
}
// Pass 2: Walk backwards through haystack, performing copy/replace
for (oldneedle_ptr = (char *)oldneedle_last;
write_ptr >= haystack;
write_ptr--, read_ptr--)
{
*write_ptr = *read_ptr;
bool found = locate_backward(&oldneedle_ptr, read_ptr,
oldneedle, oldneedle_last);
if (found) {
// then perform replacement
write_ptr -= diff_len;
memcpy(write_ptr, newneedle, newneedle_len);
}
}
return SUCCESS;
}
}
// locate_forward: compare needle_ptr and read_ptr to see if a match occured
// needle_ptr is updated as appropriate for the next call
// return true if match occured, false otherwise
static inline bool
locate_forward(char **needle_ptr, char *read_ptr,
const char *needle, const char *needle_last)
{
if (**needle_ptr == *read_ptr) {
(*needle_ptr)++;
if (*needle_ptr > needle_last) {
*needle_ptr = (char *)needle;
return true;
}
}
else
*needle_ptr = (char *)needle;
return false;
}
// locate_backward: compare needle_ptr and read_ptr to see if a match occured
// needle_ptr is updated as appropriate for the next call
// return true if match occured, false otherwise
static inline bool
locate_backward(char **needle_ptr, char *read_ptr,
const char *needle, const char *needle_last)
{
if (**needle_ptr == *read_ptr) {
(*needle_ptr)--;
if (*needle_ptr < needle) {
*needle_ptr = (char *)needle_last;
return true;
}
}
else
*needle_ptr = (char *)needle_last;
return false;
}
Example usage
#define BUF 30
char *retval1, *retval2;
char message[BUF] = "Your name is $USERNAME.";
char username[] = "admin";
char username_toolong[] = "System Administrator";
int main() {
retval1 = str_replace(message, BUF, "$USERNAME", username_toolong);
retval2 = str_replace(message, BUF, "$USERNAME", username);
if (!retval1)
printf("Not enough room to replace $USERNAME with `%s'\n", username_toolong);
if (!retval2)
printf("Not enough room to replace $USERNAME with `%s'\n", username);
printf("%s\n", message);
return 0;
}
Output
Not enough room to replace $USERNAME with `System Administrator'
Your name is admin.
Cheers.
Knuth-Morris-Pratt (which is classic) or Boyer-Moore (which is sometimes faster)?
http://en.wikipedia.org/wiki/Knuth-Morris-Pratt_algorithm
http://en.wikipedia.org/wiki/Boyer-Moore_string_search_algorithm
Try using a Google search for 'string searching algorithms'.
I can't help but wonder what algorithm strstr() implements. Given that these are fairly standard algorithms, it's entirely possible that a good implementation of strstr() uses one of them.
However there's no guarantee that strstr() implements an optimised algorithm or that the same algorithm is used from one platform to another.
Using std::string (from <string>) you can simply use find and replace.
http://www.cplusplus.com/reference/string/string/find/ - Gets you an index.
http://www.cplusplus.com/reference/string/string/replace/ - Takes an index.
Edit: Touché. This is for C++ only.
Is this any good to you?
http://www.daniweb.com/forums/thread51976.html
here is a nice code
#include <stdio.h>
#include <string.h>
char *replace_str(char *str, char *orig, char *rep)
{
static char buffer[4096];
char *p;
if(!(p = strstr(str, orig))) // Is 'orig' even in 'str'?
return str;
strncpy(buffer, str, p-str); // Copy characters from 'str' start to 'orig' st$
buffer[p-str] = '\0';
sprintf(buffer+(p-str), "%s%s", rep, p+strlen(orig));
return buffer;
}
int main(void)
{
puts(replace_str("Hello, world!", "world", "Miami"));
return 0;
}
My solution, based on the others, but a bit safer I believe:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_SOURCE_SIZE (0x100000)
char * searchReplace(char * string, char *toReplace[], char *replacements[], int numReplacements){
int i = 0;
char *locOfToRep;
char *toRep;
char *rep;
int lenToRep,lenStr,lenAfterLocRep;
static char buffer[MAX_SOURCE_SIZE];
for(i = 0; i < numReplacements; ++i){
toRep = toReplace[i];
rep = replacements[i];
//if str not in the string, exit.
if (!(locOfToRep = strstr(string,toRep))){
exit(EXIT_FAILURE);
}
lenToRep = strlen(toRep);
lenStr = strlen(string);
lenAfterLocRep = strlen(locOfToRep);
//Print the string upto the pointer, then the val, and then the rest of the string.
sprintf(buffer, "%.*s%s%s", lenStr-lenAfterLocRep, string,rep,locOfToRep+lenToRep);
string = buffer;
}
return buffer;
}
int main(){
char * string = "Hello, world!";
int numVals;
char *names[2] = {"Hello", "world"};
char *vals[2] = {"Goodbye", "you"};
numVals = 2;
string = searchReplace(string, names, vals, numVals);
printf("%s\n",string);
}