Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I have this
A > B , or A < B , or A==B ,
using the strtok I will destroy the data , and my goal is to get some kind of a structure where I can examine :
what kind of delimiter I had
get access to both sides of it (A and B).
so:
if ( > )
do something with A and B
else if (==)
do something with A and B
I know it sound simple , but it always comes to be cumbersome .
EDIT:
What i did was this, seems like too long for the task :
for (int k=1;k<strlen(p);k++)
{
char left[4]="" ;
char right[12]="" ;
switch(p[k])
{
case '>' :
{
long num =strstr(p,">") - p ;
strncpy(left,p,num);
strncpy(right,p+num+1,strlen(p)-num-1);
break;
}
case '<' :
{
long num =strstr(p,"<") - p ;
strncpy(left,p,num);
strncpy(right,p+num+1,strlen(p)-num-1);
break;
}
case '=' :
{
long num =strstr(p,"=") - p ;
strncpy(left,p,num);
strncpy(right,p+num+1,strlen(p)-num-1);
break;
}
case '!' :
{
long num =strstr(p,"!") - p ;
strncpy(left,p,num);
strncpy(right,p+num+1,strlen(p)-num-1);
break;
}
default :
{}
}
}
For simple situations where you just want to parse simple strings consisting of two operands and one operator, no "expressions" this might work
#include <stdio.h>
#include <string.h>
int
main(void)
{
const char *string = "A > B";
char lho[100];
char op[3];
char rho[100];
if (sscanf(string, "%99[^=><]%2[=><]%99[^=><]", lho, op, rho) == 3) {
fprintf(stdout, "left hand operand: %s\n", lho);
fprintf(stdout, "operator: %s\n", op);
fprintf(stdout, "right hand operand: %s\n", rho);
}
return 0;
}
This is by no means the best way to do it, it just shows that you can use it. Also, I didn't think a lot about it, I wrote the code to show you a possible solution. I don't actually like it, and I wouldn't use it
Here is a generalized procedure:
For a given set delimiters, use strstr to check each if it appears in the input string. As a bonus, my code below allows 'double' entries such as < and <>; it checks all and use the longest possible.
After determining the best delimiter to use, you have a pointer to its start. Then you can
.. copy everything at its left into a left variable;
.. copy the delimiter itself into a delim variable (for consistency); and
.. copy everything to the right of the delimiter into a right variable.
Point 4 is 'for consistency' with the other two variables. You could also create an enumeration (LESS, EQUALS, MORE, NOT_EQUAL (in my example)) and return that instead, because the set of possibilities is limited to these.
In code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
const char *delimiters[] = {
"<", ">", "==", "<>", NULL
};
int split_string (const char *input, char **dest_left, char **dest_delim, char **dest_right)
{
int iterator;
int best_fit_delim;
char *ptr;
/* (optionally) clean whitespace at start */
while (isspace(*input))
input++;
/* look for the longest delimiter we can find */
best_fit_delim = -1;
iterator = 0;
while (delimiters[iterator])
{
ptr = strstr (input, delimiters[iterator]);
if (ptr)
{
if (best_fit_delim == -1 || strlen(delimiters[iterator]) > strlen(delimiters[best_fit_delim]))
best_fit_delim = iterator;
}
iterator++;
}
/* did we find anything? */
if (best_fit_delim == -1)
return 0;
/* reset ptr to this found one */
ptr = strstr (input, delimiters[best_fit_delim]);
/* copy left hand side */
iterator = ptr - input;
/* clean whitespace at end */
while (iterator > 0 && isspace(input[iterator-1]))
iterator--;
*dest_left = malloc (iterator + 1);
memcpy (*dest_left, input, iterator);
(*dest_left)[iterator] = 0;
/* the delimiter itself */
*dest_delim = malloc(strlen(delimiters[best_fit_delim])+1);
strcpy (*dest_delim, delimiters[best_fit_delim]);
/* update the pointer to point to *end* of delimiter */
ptr += strlen(delimiters[best_fit_delim]);
/* skip whitespace at start */
while (isspace(*ptr))
ptr++;
/* copy right hand side */
*dest_right = malloc (strlen(ptr) + 1);
strcpy (*dest_right, ptr);
return 1;
}
int main (void)
{
char *source_str = "A <> B";
char *left, *delim, *right;
if (!split_string (source_str, &left, &delim, &right))
{
printf ("invalid input\n");
} else
{
printf ("left: \"%s\"\n", left);
printf ("delim: \"%s\"\n", delim);
printf ("right: \"%s\"\n", right);
free (left);
free (delim);
free (right);
}
return 0;
}
resulting, for A <> B, in
left: "A"
delim: "<>"
right: "B"
The code can be a bit smaller if you only need to check your list of <, ==, and >; then you can use strchr, for single characters (and if = is found, check the next character). You can also forget the best_fit length check, as there can be only one that fits.
The code removes whitespace only around the comparison operator. For consistency, you may want to remove all whitespace at the start and end of the input; then, invalid input can be detected by the return left or right variables having a length of 0 – i.e., they only contain the 0 string terminator. You still need to free those zero-length strings.
For fun, you can add "GT","LT","GE","LE" to the delimiters and see how it does on strings such as A GT B, ALLEQUAL, and FAULTY<MATCH.
Related
i want to replace _ (underscore) with white spaces and make the first letter of the name and the surname to upper case while printing the nameList in searchKeyword method.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void searchKeyword(const char * nameList[], int n, const char keyword[])
{
int i,name=0;
char *str;
const char s[2] = " " ;
for(i=0;i<n;i++)
{
char *str = (char *) malloc((strlen(nameList[0])+1)*sizeof(char));
strcpy(str,nameList[i]);
strtok(str,"_");
if(strcmp(keyword,strtok(NULL,"_"))==0) // argument NULL will start string
{ // from last point of previous string
name++;
if(nameList[i] == '_')
strcpy(nameList[i],s);
//nameList[i] = ' ';
printf("%s\n",nameList[i]);
}
}
if(name==0)
{
printf("No such keyword found\n");
}
free(str); //deallocating space
}
int main()
{
char p1[] = "zoe_bale";
char p2[] = "sam_rodriguez";
char p3[] = "jack_alonso";
char p4[] = "david_studi";
char p5[] = "denzel_feldman";
char p6[] = "james_bale";
char p7[] = "james_willis";
char p8[] = "michael_james";
char p9[] = "dustin_bale";
const char * nameList[9] = {p1, p2, p3, p4, p5, p6, p7, p8, p9};
char keyword[100];
printf("Enter a keyword: ");
scanf("%s", keyword);
printf("\n");
searchKeyword(nameList, 9, keyword);
printf("\n");
for (int i = 0; i < 9; i++)
printf("%s\n",nameList[i]);
return 0;
}
Search through the strings and print the ones whose surname part is equal to keyword.
As shown in the example runs below, the strings are printed in “Name Surname” format (the first letters are capitalized).
Output should be like this:
Enter a keyword: james
Michael James
zoe_bale
sam_rodriguez
jack_alonso
david_studi
denzel_feldman
james_bale
james_willis
michael_james
dustin_bale
There is no reason to dynamically allocate storage for your name and surname. Looking at your input, neither will exceed 9-characters, so simply using an array for each of 64-chars provides 6X the storage required (if you are unsure, double that to 128-chars and have 1200% additional space). That avoids the comparatively expensive calls to malloc.
To check whether keyword exists in nameList[i], you don't need to separate the values first and then compare. Simply use strstr (nameList[i], keyword) to determine if keyword is contained in nameList[i]. If you then want to match only the name or surname you can compare again after they are separated. (up to you)
To parse the names from the nameList[i] string, all you need is a single pointer to locate the '_' character. A simple call to strchr() will do and it does not modify nameList[i] so there is no need to duplicate.
After using strchr() to locate the '_' character, simply memcpy() from the start of nameList[i] to your pointer to your name array, increment the pointer and then strcpy() from p to surname. Now you have separated name and surname, simply call toupper() on the first character of each and then output the names separate by a space, e.g.
...
#include <ctype.h>
#define NLEN 64
void searchKeyword (const char *nameList[], int n, const char keyword[])
{
for (int i = 0; i < n; i++) { /* loop over each name in list */
if (strstr (nameList[i], keyword)) { /* does name contain keyword? */
char name[NLEN], surname[NLEN]; /* storage for name, surname */
const char *p = nameList[i]; /* pointer to parse nameList[i] */
if ((p = strchr(p, '_'))) { /* find '_' in nameList[i] */
/* copy first-name to name */
memcpy (name, nameList[i], p - nameList[i]);
name[p++ - nameList[i]] = 0; /* nul-terminate first name */
*name = toupper (*name); /* convert 1st char to uppwer */
/* copy last name to surname */
strcpy (surname, p);
*surname = toupper (*surname); /* convert 1st char to upper */
printf ("%s %s\n", name, surname); /* output "Name Surname" */
}
}
}
}
Example Use/Output
Used with the remainder of your code, searching for "james" locates those names containing "james" and provides what looks like the output you requested, e.g.
$ ./bin/keyword_surname
Enter a keyword: james
James Bale
James Willis
Michael James
zoe_bale
sam_rodriguez
jack_alonso
david_studi
denzel_feldman
james_bale
james_willis
michael_james
dustin_bale
(note: to match only the name or surname add an additional strcmp before the call to printf to determine which you want to output)
Notes On Your Existing Code
Additional notes continuing from the comments on your existing code,
char *str = (char *) malloc((strlen(nameList[0])+1)*sizeof(char));
should simply be
str = malloc (strlen (nameList[i]) + 1);
You have previously declared char *str; so the declaration before your call to malloc() shadows your previous declaration. If you are using gcc/clang, you can add -Wshadow to your compile string to ensure you are warned of shadowed variables. (they can have dire consequences in other circumstances)
Next, sizeof (char) is always 1 and should be omitted from your size calculation. There is no need to cast the return of malloc() in C. See: Do I cast the result of malloc?
Your comparison if (nameList[i] == '_') is a comparison between a pointer and integer and will not work. Your compiler should be issuing a diagnostic telling you that is incorrect (do not ignore compiler warnings -- do not accept code until it compiles without warning)
Look things over and let me know if you have further questions.
that worked for me and has no memory leaks.
void searchKeyword(const char * nameList[], int n, const char keyword[])
{
int found = 0;
const char delim = '_';
for (int i = 0; i < n; i++) {
const char *fst = nameList[i];
for (const char *tmp = fst; *tmp != '\0'; tmp++) {
if (*tmp == delim) {
const char *snd = tmp + 1;
int fst_length = (snd - fst) / sizeof(char) - 1;
int snd_length = strlen(fst) - fst_length - 1;
if (strncmp(fst, keyword, fst_length) == 0 ||
strncmp(snd, keyword, snd_length) == 0) {
found = 1;
printf("%c%.*s %c%s\n",
fst[0]-32, fst_length-1, fst+1,
snd[0]-32, snd+1);
}
break;
}
}
}
if (!found)
puts("No such keyword found");
}
hopefully it's fine for you too, although I use string.h-functions very rarely.
I have the following problem, I have a string that comes with x terms, and some are in parentheses. I need to be able to separate the terms that are in parentheses and place them in the nodes of a list:
The first node in the list contains the entire character string, then the terms that are in parentheses are stored in the following nodes.
Something like this:
String: a*(b+(c+j)-h)*2 + (a+(b-c))
So, in list:
Firts node :
a*(b+(c+j)-h)*2+(a+(b-c))->(b+(c+j)-h)->(c+j)->(a+(b-c))->(b-c)
I need ideas to implement the algorithm of separation of terms, I am stuck with that part. I have already implemented all the lists part.
The function they ask me for is
void separate (char * s)
Recursion is a common way to parse nested structures, as #SomeProgrammerDude commented.
My intuition for the algorithm that you are looking for is this:
1) Recursively call the separate method.
2) Every call should parse one term enclosed in parentheses, and insert it at the end of our list.
3) The method has to two modes: iterate over the input string and iterate over the input string while filling up the term.
We are looking for the first occurrence of an opening parenthesis; once this is found, the method enables the "read" mode, and starts copying everything in its path to a local buffer, until the closing parentheses is found.
When that happens, the method disables the "read" mode, flagging that the term is now ready for insertion in the list.
4) How to bypass nested terms? Once the 1st opening parenthesis is found, maintain a counter of parentheses, which is adjusted according to the number of parentheses met (+1 for an opening parenthesis, -1 for a closing one).
If an opening parenthesis is met, the counter gets incremented by 1. If the counter is greater than 1, that signals us that a nested term is found, and thus we shouldn't stop when its closing parentheses is met, but instead continue, while decrementing the counter by 1.
5) Once a term is inserted, then we should recursively call our separate method, where now the input string should be the already parsed input, starting from the character after the first opening parenthesis that we found.
6) Base case of the recursion? When all the input is consumed, and we reached the NULL string terminator.
Full code example (uncomment print statements that show the status as the program progresses):
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct listnode *Listptr;
struct listnode {
char* value;
Listptr next;
};
void insert_at_end(Listptr *, char *);
void print(Listptr);
void free_list(Listptr *);
void separate(Listptr *list, char *s)
{
if(!*s)
return;
int parentheses = 0, read = -1, i = 0;
char term[16] = {0}, *opening_parenthesis;
//printf("Before while input is %s\n", s);
while(*s)
{
//printf("#parentheses = %d, read = %d, i = %d, term = %s\n", parentheses, read, i, term);
if(*s == '(')
{
if(parentheses == 0)
opening_parenthesis = s;
read = 1;
parentheses++;
}
else if(*s == ')')
{
if(parentheses > 1)
parentheses--;
else if(parentheses == 1)
{
term[i++] = *s;
read = 0;
}
}
if(read == 1)
{
term[i++] = *s;
//puts(term);
}
else if (read == 0)
{
insert_at_end(list, term);
separate(list, opening_parenthesis + 1);
return;
}
s++;
}
}
int main(void)
{
char buf[128];
fgets(buf, sizeof(buf), stdin);
// eat trailing newline of fgets
if(!strlen(buf))
{
printf("No input, exiting..\n");
return EXIT_FAILURE;
}
// eat trailing newline of fgets
buf[strlen(buf)] = '\0';
// Goal: a*(b+(c+j)-h)*2+(a+(b-c))->(b+(c+j)-h)->(c+j)->(a+(b-c))->(b-c)
Listptr list = NULL;
insert_at_end(&list, buf);
//printf("First node: "); print(list);
separate(&list, buf);
print(list);
free_list(&list);
return EXIT_SUCCESS;
}
void insert_at_end(Listptr *ptraddr, char* str)
{ /* Insert str as last element of list *ptraddr */
while (*ptraddr != NULL) /* Go to end of list */
ptraddr = &((*ptraddr)->next);/* Prepare what we need to change */
/* In real application, check for NULL pointer of malloc! */
*ptraddr = malloc(sizeof(struct listnode)); /* Space for new node */
/* Space for string. Length of str + 1 for the null terminator */
(*ptraddr)->value = malloc((strlen(str) + 1) * sizeof(char));
strcpy((*ptraddr)->value, str); /* Copy str */
(*ptraddr)->next = NULL; /* There is no next element */
}
void print(Listptr list) /* Print elements of list */
{
while (list != NULL) { /* Visit list elements up to the end */
printf("%s--> ", list->value); /* Print current element */
list = list->next; /* Go to next element */
}
printf("NULL\n"); /* Print end of list */
}
void free_list(Listptr *ptraddr)
{
Listptr templist = *ptraddr;
while(*ptraddr != NULL) {
*ptraddr = (*ptraddr)->next;
free(templist->value);
free(templist);
templist = *ptraddr;
}
*ptraddr = NULL;
}
Output (for your input):
a*(b+(c+j)-h)*2 + (a+(b-c))--> (b+(c+j)-h)--> (c+j)--> (a+(b-c))--> (b-c)--> NULL
Note1: I altered the prototype of your separate method to allow for the list to be passed also as a parameter. I guess in your implementation the list is a global variable or something, which in general should be avoided.
Note2: It could have been implemented without the usage of the read flag, by using just the variable for the number of parentheses to determine when to read (when that number positive), and you could assign a reserved value (-1 for example), to designate when reading is done, and the term is ready for list insertion.
Assumption1: Term's length is 15 characters at most. The code should typically check that this length is not surpassed - not done in my implementation.
Assumption2: It is assumed that term is valid, i.e. it contains the same number of opening and closing parentheses. In a real-world scenario one should sanitize the input.
Live demo
PS: I have the list implementation in strList(C) also.
John Bollinger recommended:
Presumably, a recursive function for the purpose would return information about how much of the string had been parsed, so that its caller could\ pick up with the remainder of the string, if any. That implies that it would not necessarily be separate() itself that is recursive, but rather some helper function that it calls.
OP already sketched (in comment):
If given a function it returns a substring with what is inside the two parentheses I can insert it in my list. And then I can call that function back with recursion as they told me above.
This is where I started.
There come various methods in mind to build substrings:
modify original string by overwriting a character with a delimiter '\0' (may be, temporarily) – like done e.g. in strtok()
allocate memory for substrings and copy portions of original string (using something like e.g. strdup())
just return length (and, may be, start) of substring
I used the third option.
#include <assert.h>
#include <stdio.h>
#include <string.h>
void add_term(char *s, size_t len)
{
printf("'%.*s'\n", (int)len, s);
}
size_t find_term(char *s, size_t len)
{
assert(*s == '(');
int n = 1;
size_t i = 1;
for (; i < len && n; ++i) n += (s[i] == '(') - (s[i] == ')');
return n ? fprintf(stderr, "ERROR!\n"), 0 : i;
}
void separate_terms(char *s, size_t lenTotal, int addTotal)
{
for (size_t i = 0; i < lenTotal;) {
switch (s[i]) {
case '(': {
const size_t len = find_term(s + i, lenTotal - i);
if (!len) return;
if (len < lenTotal + addTotal) add_term(s + i, len);
separate_terms(s + i + 1, len - 2, 1);
i += len;
} break;
case ')': fprintf(stderr, "ERROR!\n"); return;
default: ++i;
}
}
}
void separate(char *s)
{
size_t lenTotal = strlen(s);
printf("Term: "); add_term(s, lenTotal);
separate_terms(s, lenTotal, 0);
}
int main(void)
{
// sample of OP:
separate("a*(b+(c+j)-h)*2 + (a+(b-c))");
}
Output:
Term: 'a*(b+(c+j)-h)*2 + (a+(b-c))'
'(b+(c+j)-h)'
'(c+j)'
'(a+(b-c))'
'(b-c)'
Notes:
OP stated that storage of results in lists (with appropriate management) is already solved. Hence, I used simple console output instead (in add_term()).
find_term() is simply counting opening and closing parentheses until the closing parenthesis corresponding to the first opening is found (success) or the string end is reached (error case).
separate_terms() is the recursive descent scanner to find sub-terms in a term.
It iterates over characters of input string. Every time an opening parenthesis (() is found, it calls find_term() to determine the length of sub-term and add the result. The found sub-term is analized recursively by calling itself recursively to the restricted length. Afterwards, the length of subterm is skipped because its fully analyzed now.
While fiddling with edge cases, I found out that my initial (significantly shorter) version reported a duplicated term when the complete input term was in parentheses (e.g. (a + b)). Hence, I added a flag addTotal to denote whether a found subterm shall be added if it has the total length of input.
separate() is rather short. It's just a wrapper to add a term for ful input and to perform the toplevel call of the recursive separate_terms(). (0 is passed for addTotal to prevent duplicate adding of complete input.)
I made some other samples which I considered as edge cases for my solution to check for potential bugs:
// valid edge cases:
separate(""); // valid?
separate("()"); // valid?
separate("a");
separate("(a + b)");
separate("(a + b) * 2");
separate("(a + b) * (c - d)");
separate("((a + b))");
// invalid cases:
separate("(");
separate("((");
separate(")");
separate("))");
separate("())(()");
separate("a(a(a");
separate("((a)))");
Output:
Term: ''
Term: '()'
Term: 'a'
Term: '(a + b)'
Term: '(a + b) * 2'
'(a + b)'
Term: '(a + b) * (c - d)'
'(a + b)'
'(c - d)'
Term: '((a + b))'
'(a + b)'
Term: '('
ERROR!
Term: '(('
ERROR!
Term: ')'
ERROR!
Term: '))'
ERROR!
Term: '())(()'
'()'
ERROR!
Term: 'a(a(a'
ERROR!
Term: '((a)))'
'((a))'
'(a)'
ERROR!
Live Demo on coliru
I have a simple C program that is supposed to expand the string FX according to the following rules:
X -> X+YF+
Y-> -FX-Y
The program is as follows:
#include <stdio.h>
void expandOnce( )
{
char* s = (char*)malloc(sizeof(char)*100);
int i=0;
char str[]="FX";
while(str[i]!='\0')
{
if(str[i]=='X')
{
s[i]="X+YF+";
}
if(str[i]=='Y')
{
s[i]="-FX-Y";
}
i++;
}
printf("%s",s);
}
void expandNtimes (int n)
{
for (int i =0; i < n; i++){
expandOnce();
}
}
int main(){
expandNtimes(2);
return 0;
}
If the program executes correctly, it should print out:
FX+YF++-FX-YF+
This is after 2 expansions of FX using the above rules.
Questions:
1. How can you make this work without printing out gibberish?
2. How can I return the expanded array from expandNtimes() and expandOnce() so that I can, for instance, use it in the main function?
I try this but I keep getting memory errors.
After your suggestions, I made the following changes:
#include <stdio.h>
#include <string.h>
#define NTIMES 2
#define MAXC 100
void expandOnce( )
{
char s[MAXC];
int i=0;
s[0]='F';
s[1]='X';
while(s[i]!='\0')
{
if(s[i]=='X'){
//shift all letters to the right by 5 steps
for (i; i < MAXC; i++){ //warning: statement with no effect (Wunused value)
s[i + 5]= s[i];
if(s[i]=='\0'){
break;}
}
//Fill in the expansion
s[i]='X';
s[i+1] ='+';
s[i+2] ='Y';
s[i+3]='F';
s[i+4] ='+';
}
if(s[i]=='Y'){
//shift all letters to the right by 5 steps
for (i; i < MAXC; i++){ //warning: statement with no effect (Wunused value)
s[i + 5]=s[i];
if(s[i]=='\0'){
break;}
}
//Fill in the expansion
s[i]='-';
s[i+1] ='F';
s[i+2] ='X';
s[i+3]='-';
s[i+4] ='Y';
}
i++;
}
printf("%s\n",s);
printf("Me\n");
}
void expandNtimes (int n)
{
for (int i =0; i < n; i++){
expandOnce();
}
}
int main(){
expandOnce();
expandNtimes(NTIMES);
return 0;
}
Both of my for loops have a warning warning: statement with no effect (Wunused value) which I do not understand. Finally, I get this error:
Segmentation fault (core dumped)
Is it allowed to do a for-loop inside a while-loop?
Oh Boy... Do you have a whole list of "you can't do that..." in your code.
To begin with there is no need to cast the return of malloc, it is unnecessary. See: Do I cast the result of malloc?.
char *s = malloc (sizeof *s * 100);
is all that is needed (note: if you always use sizeof dereference_pointer you will always have your type size correct.
This brings up another point, if you need constants #define one (or more) or use a global enum to accomplish the same thing, e.g.
#define NTIMES 2
#define MAXC 100
or
enum { NTIMES = 2, MAXC = 100 };
Then you can use them like,
char *s = malloc (sizeof *s * MAXC);
and
expandNtimes(NTIMES);
By defining constants, you then have one convenient place at the top of your code to make changes if needed in the future and not have to pick through each allocation or function call changing all your hardcoded magic numbers.
Your Memory Leak
You allocate for s in expandOnce, but never free s and don't return a pointer so that it could be later freed in main() (or any other calling function).
You should include free (s); after printf("%s",s); (which you should also include a newline in to prevent multiple outputs from running together, and so that your program is POSIX compliant -- outputting a final '\n'), e.g. printf("%s\n",s);
Moreover, "Why are you dynamically allocating anyway?" Just use a fixed buffer, you are not trying to return it. Just use:
char s[MAXC] = "";
s is Uninitialized and You Leave s[0] Uninitialized
s[i]="X+YF+"; and s[i]="-FX-Y"; write 4-characters to s from index 1. s[0] is never initialized which causes any subsequent attempt to read from s invoke Undefined Behavior. You cannot simply assign the pointer to string literal "X+YF+"; to a character s[i] -- your compiler should be screaming warnings and errors at you.
You can copy the literal to s with:
strcpy (s, "X+YF+");
or you can simply loop repeatedly copying as you go, e.g.
int i;
for (i = 0; str[i]; i++) /* loop over each char in str */
s[i] = str[i]; /* assign to s */
s[i] = 0; /* don't forget to nul-terminate s */
Compile with Warnings Enabled
Always compile with warnings enabled, and do not accept code until it compiles cleanly without warning. To enable warnings add -Wall -Wextra to your gcc or clang compile string. (add -pedantic for several additional warnings). For clang, instead you can use -Weverything. For VS (cl.exe on windoze), add /W3 (or use /Wall to enable all warnings).
Read and understand each warning. They will identify any problems, and the exact line on which they occur. You can learn as much about coding by simply listening to what your compiler is telling you as you can from most tutorials.
Put these suggestions to use and then edit your question (or ask a new one) if you have further problems.
Additional Comments After Edit
Gakuo, it is obvious you are still struggling to sort out string/character array handling in order to make the expansions work. As I mentioned in the comments, whenever you have a problem like this, do not pick up the keyboard and start pecking away hoping that you can tinker long enough that divine intervention will somehow guide you to a solution (it won't...).
Instead first pick up a 8 1/2 x 11 sheet of paper (graph paper works really well) and write out your original string, and then plan each step required to get you from your original string to the final string you need (don't forget to represent the '\0' in your layout as well)
For example, you could start with your original string:
+---+---+---+
| F | X |\0 |
+---+---+---+
The next step would be to represent the shift to make room for your expansion (you leave the original character in place since you will simply overwrite it):
+---+---+---+---+---+---+---+
| F | X | | | | |\0 |
+---+---+---+---+---+---+---+
Now it is a matter of copying "X+YF+" to the position of 'X' resulting in:
+---+---+---+---+---+---+---+
| F | X | + | Y | F | + |\0 |
+---+---+---+---+---+---+---+
Then simply repeat this process until you have fully exanded N times. As you do, you will be able to determine the pattern for expanding N times -- and that is when it is time to pick up the keyboard.
For your case, rather than manually looping everything, make use of memmove and memcpy to help shift and copy within the string. (you are free to manually shift and copy by looping -- as long as you can find more letters for you loop variable than just 'i'). Letting the memory functions help, you could do something like:
(note: edited to accommodate changing length of s in expandonce())
#include <stdio.h>
#include <string.h>
#define NTIMES 2
#define MAXC 100
#define SDEF "FX" /* string (default) */
#define XEXP "X+YF+" /* X expansion */
#define YEXP "-FX-Y" /* Y expansion */
/* returns pointer to 1-past last expansion on success, NULL otherwise */
char *expandonce (char *s)
{
char *p = s,
*expanded = NULL;
size_t lxexp = strlen (XEXP),
lyexp = strlen (YEXP);
while (*p) {
if (*p == 'X') { /* handle 'X' found */
size_t lens = strlen (s); /* get new length of s */
if (MAXC > lens + lxexp) { /* room to expand? */
size_t lenp = strlen (p); /* total to shift */
/* shift chars to right of 'X' by lxexp-1 including '\0' */
memmove (p + lxexp, p + 1, lenp + lxexp - 1);
memcpy (p, XEXP, lxexp); /* copy expansion */
p += lxexp; /* add offset */
expanded = p; /* set return */
}
}
else if (*p == 'Y') { /* handle 'Y' found */
size_t lens = strlen (s); /* same for 'Y' */
if (MAXC > lens + lyexp) {
size_t lenp = strlen (p);
memmove (p + lyexp, p + 1, lenp + lyexp - 1);
memcpy (p, YEXP, lyexp);
p += lyexp;
expanded = p;
}
}
else /* handle all other chars */
p++;
}
return expanded;
}
/* returns number of successful expansion loops */
int expandntimes (char *s, int n)
{
int i = 0;
char *p = s;
for (i = 0; i < n; i++)
if ((p = expandonce (s)) == NULL)
break;
return i;
}
int main (int argc, char **argv) {
char str[MAXC] = "";
int n = 0;
if (argc > 1 && strlen (argv[1]) < MAXC - 1)
strcpy (str, argv[1]);
else
strcpy (str, SDEF);
printf ("string: %s\nX_exp : %s\nY_exp : %s\n\n", str, XEXP, YEXP);
n = expandntimes (str, NTIMES);
if (n == 0) {
fputs ("error: no expansions possible.\n", stderr);
return 1;
}
printf ("%d expansions => %s\n", n, str);
return 0;
}
(note: this is a minimum example -- you should verify that all corner cases are covered as you step through your design)
Example Use/Output
Your example:
$ ./bin/expand2 "FX"
string: FX
X_exp : X+YF+
Y_exp : -FX-Y
2 expansions => FX+YF++-FX-YF+
A slightly different string:
$ ./bin/expand2 "XY"
string: XY
X_exp : X+YF+
Y_exp : -FX-Y
2 expansions => X+YF++-FX-YF+-FX+YF+--FX-Y
You getting memory errors because you try to write in memory where are you not supposed to do anything.if you want to append string you must use strcat() function! Line s[i]="X+YF+"; will never compile because you try to write multiple characters in place where is allowed only one character. i think it is better to make s global and append charracters one by one to s with strcat until you make string. You can access to global variables in main.Then print string s.
Right now, I'm attempting to familiarize myself with C by writing a function which, given a string, will replace all instances of a target substring with a new substring. However, I've run into a problem with a reallocation of a char* array. To my eyes, it seems as though I'm able to successfully reallocate the array string to a desired new size at the end of the main loop, then perform a strcpy to fill it with an updated string. However, it fails for the following scenario:
Original input for string: "use the restroom. Then I need"
Target to replace: "the" (case insensitive)
Desired replacement value: "th'"
At the end of the loop, the line printf("result: %s\n ",string); prints out the correct phrase "use th' restroom. Then I need". However, string seems to then reset itself: the call to strcasestr in the while() statement is successful, the line at the beginning of the loop printf("string: %s \n",string); prints the original input string, and the loop continues indefinitely.
Any ideas would be much appreciated (and I apologize in advance for my flailing debug printf statements). Thanks!
The code for the function is as follows:
int replaceSubstring(char *string, int strLen, char*oldSubstring,
int oldSublen, char*newSubstring, int newSublen )
{
printf("Starting replace\n");
char* strLoc;
while((strLoc = strcasestr(string, oldSubstring)) != NULL )
{
printf("string: %s \n",string);
printf("%d",newSublen);
char *newBuf = (char *) malloc((size_t)(strLen +
(newSublen - oldSublen)));
printf("got newbuf\n");
int stringIndex = 0;
int newBufIndex = 0;
char c;
while(true)
{
if(stringIndex > 500)
break;
if(&string[stringIndex] == strLoc)
{
int j;
for(j=0; j < newSublen; j++)
{
printf("new index: %d %c --> %c\n",
j+newBufIndex, newBuf[newBufIndex+j], newSubstring[j]);
newBuf[newBufIndex+j] = newSubstring[j];
}
stringIndex += oldSublen;
newBufIndex += newSublen;
}
else
{
printf("old index: %d %c --> %c\n", stringIndex,
newBuf[newBufIndex], string[stringIndex]);
newBuf[newBufIndex] = string[stringIndex];
if(string[stringIndex] == '\0')
break;
newBufIndex++;
stringIndex++;
}
}
int length = (size_t)(strLen + (newSublen - oldSublen));
string = (char*)realloc(string,
(size_t)(strLen + (newSublen - oldSublen)));
strcpy(string, newBuf);
printf("result: %s\n ",string);
free(newBuf);
}
printf("end result: %s ",string);
}
At first the task should be clarified regarding desired behavior and interface.
The topic "Char array..." is not clear.
You provide strLen, oldSublen newSublen, so it looks that you indeed want to work just with bulk memory buffers with given length.
However, you use strcasestr, strcpy and string[stringIndex] == '\0' and also mention printf("result: %s\n ",string);.
So I assume that you want to work with "null terminated strings" that can be passed by the caller as string literals: "abc".
It is not needed to pass all those lengths to the function.
It looks that you are trying to implement recursive string replacement. After each replacement you start from the beginning.
Let's consider more complicated sets of parameters, for example, replace aba by ab in abaaba.
Case 1: single pass through input stream
Each of both old substrings can be replaced: "abaaba" => "abab"
That is how the standard sed string replacement works:
> echo "abaaba" | sed 's/aba/ab/g'
abab
Case 2: recursive replacement taking into account possible overlapping
The first replacement: "abaaba" => "ababa"
The second replacement in already replaced result: "ababa" => "abba"
Note that this case is not safe, for example replace "loop" by "loop loop". It is an infinite loop.
Suppose we want to implement a function that takes null terminated strings and the replacement is done in one pass as with sed.
In general the replacement cannot be done in place of input string (in the same memory).
Note that realloc may allocate new memory block with new address, so you should return that address to the caller.
For implementation simplicity it is possible to calculate required space for result before memory allocation (Case 1 implementation). So reallocation is not needed:
#define _GNU_SOURCE
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
char* replaceSubstring(const char* string, const char* oldSubstring,
const char* newSubstring)
{
size_t strLen = strlen(string);
size_t oldSublen = strlen(oldSubstring);
size_t newSublen = strlen(newSubstring);
const char* strLoc = string;
size_t replacements = 0;
/* count number of replacements */
while ((strLoc = strcasestr(strLoc, oldSubstring)))
{
strLoc += oldSublen;
++replacements;
}
/* result size: initial size + replacement diff + sizeof('\0') */
size_t result_size = strLen + (newSublen - oldSublen) * replacements + 1;
char* result = malloc(result_size);
if (!result)
return NULL;
char* resCurrent = result;
const char* strCurrent = string;
strLoc = string;
while ((strLoc = strcasestr(strLoc, oldSubstring)))
{
memcpy(resCurrent, strCurrent, strLoc - strCurrent);
resCurrent += strLoc - strCurrent;
memcpy(resCurrent, newSubstring, newSublen);
resCurrent += newSublen;
strLoc += oldSublen;
strCurrent = strLoc;
}
strcpy(resCurrent, strCurrent);
return result;
}
int main()
{
char* res;
res = replaceSubstring("use the restroom. Then I need", "the", "th");
printf("%s\n", res);
free(res);
res = replaceSubstring("abaaba", "aba", "ab");
printf("%s\n", res);
free(res);
return 0;
}
I'm trying to make a quick function that gets a word/argument in a string by its number:
char* arg(char* S, int Num) {
char* Return = "";
int Spaces = 0;
int i = 0;
for (i; i<strlen(S); i++) {
if (S[i] == ' ') {
Spaces++;
}
else if (Spaces == Num) {
//Want to append S[i] to Return here.
}
else if (Spaces > Num) {
return Return;
}
}
printf("%s-\n", Return);
return Return;
}
I can't find a way to put the characters into Return. I have found lots of posts that suggest strcat() or tricks with pointers, but every one segfaults. I've also seen people saying that malloc() should be used, but I'm not sure of how I'd used it in a loop like this.
I will not claim to understand what it is that you're trying to do, but your code has two problems:
You're assigning a read-only string to Return; that string will be in your
binary's data section, which is read-only, and if you try to modify it you will get a segfault.
Your for loop is O(n^2), because strlen() is O(n)
There are several different ways of solving the "how to return a string" problem. You can, for example:
Use malloc() / calloc() to allocate a new string, as has been suggested
Use asprintf(), which is similar but gives you formatting if you need
Pass an output string (and its maximum size) as a parameter to the function
The first two require the calling function to free() the returned value. The third allows the caller to decide how to allocate the string (stack or heap), but requires some sort of contract about the minumum size needed for the output string.
In your code, when the function returns, then Return will be gone as well, so this behavior is undefined. It might work, but you should never rely on it.
Typically in C, you'd want to pass the "return" string as an argument instead, so that you don't have to free it all the time. Both require a local variable on the caller's side, but malloc'ing it will require an additional call to free the allocated memory and is also more expensive than simply passing a pointer to a local variable.
As for appending to the string, just use array notation (keep track of the current char/index) and don't forget to add a null character at the end.
Example:
int arg(char* ptr, char* S, int Num) {
int i, Spaces = 0, cur = 0;
for (i=0; i<strlen(S); i++) {
if (S[i] == ' ') {
Spaces++;
}
else if (Spaces == Num) {
ptr[cur++] = S[i]; // append char
}
else if (Spaces > Num) {
ptr[cur] = '\0'; // insert null char
return 0; // returns 0 on success
}
}
ptr[cur] = '\0'; // insert null char
return (cur > 0 ? 0 : -1); // returns 0 on success, -1 on error
}
Then invoke it like so:
char myArg[50];
if (arg(myArg, "this is an example", 3) == 0) {
printf("arg is %s\n", myArg);
} else {
// arg not found
}
Just make sure you don't overflow ptr (e.g.: by passing its size and adding a check in the function).
There are numbers of ways you could improve your code, but let's just start by making it meet the standard. ;-)
P.S.: Don't malloc unless you need to. And in that case you don't.
char * Return; //by the way horrible name for a variable.
Return = malloc(<some size>);
......
......
*(Return + index) = *(S+i);
You can't assign anything to a string literal such as "".
You may want to use your loop to determine the offsets of the start of the word in your string that you're looking for. Then find its length by continuing through the string until you encounter the end or another space. Then, you can malloc an array of chars with size equal to the size of the offset+1 (For the null terminator.) Finally, copy the substring into this new buffer and return it.
Also, as mentioned above, you may want to remove the strlen call from the loop - most compilers will optimize it out but it is indeed a linear operation for every character in the array, making the loop O(n**2).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *arg(const char *S, unsigned int Num) {
char *Return = "";
const char *top, *p;
unsigned int Spaces = 0;
int i = 0;
Return=(char*)malloc(sizeof(char));
*Return = '\0';
if(S == NULL || *S=='\0') return Return;
p=top=S;
while(Spaces != Num){
if(NULL!=(p=strchr(top, ' '))){
++Spaces;
top=++p;
} else {
break;
}
}
if(Spaces < Num) return Return;
if(NULL!=(p=strchr(top, ' '))){
int len = p - top;
Return=(char*)realloc(Return, sizeof(char)*(len+1));
strncpy(Return, top, len);
Return[len]='\0';
} else {
free(Return);
Return=strdup(top);
}
//printf("%s-\n", Return);
return Return;
}
int main(){
char *word;
word=arg("make a quick function", 2);//quick
printf("\"%s\"\n", word);
free(word);
return 0;
}