How to add a character in a string by checking the delimiter? - c

I have a string in my program where in which it need to be altered with another string value before a "/".
Source String : qos-tree/output_rate
Target String : qos-tree-2/output_rate
#include <stdio.h>
#include <string.h>
void append(char* s, char c)
{
int len = strlen(s);
s[len] = c;
s[len+1] = '\0';
}
int main(void)
{
char str[256] = "qos-tree/output_rate";
char c = "a";
append(str, c);
printf("%s\n", str);
return 0;
}
This is what i have done so far,I think the logic is wrong here.Can anyone guide me to correct it?
Once the execution is completed the source string should have a "-2" before the "/"

void insert_before_ch(char *s, const char *ins, char c){
char *p = strchr(s, c);
if(p){
size_t len = strlen(ins);
memmove(p + len, p, strlen(p)+1);
memcpy(p, ins, len);
}
}
int main(void){
char str[256] = "qos-tree/output_rate";
insert_before_ch(str, "-2", '/');
printf("%s\n", str);
return 0;
}

In your attempt, you don't look for a slash and I do not see any "-2" anywhere.
Try this instead:
#include <stdio.h>
#include <string.h>
void append(char* s, char del, char* substring) {
char origin[256];
strcpy(origin, s);
int i = 0, j = 0, z = 0;
for(; origin[i]; ++i) {
if(origin[i] != del) {
s[j++] = origin[i];
} else {
for(; substring[z]; ++z) {
s[j++] = substring[z];
}
s[j++] = origin[i];
}
}
s[j] = '\0';
}
int main(void) {
char str[256] = "qos-tree/output_rate";
char del = '/';
char* substring = "-2";
append(str, del, substring);
printf("%s\n", str);
return 0;
}
The logic is that inside the function we use origin array to remember the actual contents of the array and then we copy from origin to s (which is the actual array of main()). If we find our delimiter del, then we copy the substring in that position and continuing with copying.
Note that the length of the array should be enough to store the resulted string. In this case, it is.

I think you should make your function work with dynamic allocation, because inserting characters into the string will make the resulting string larger, so this is my suggestion
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void insert(char **str, char chr, unsigned int position)
{
int length;
char *ptr;
if (str == NULL)
return;
length = strlen(*str);
if (position >= length)
return;
ptr = realloc(*str, 2 + length);
if (ptr == NULL)
return;
*str = ptr;
memmove(ptr + position + 1, ptr + position, length - position + 1);
ptr[position] = chr;
}
int main(void)
{
const char *source = "qos-tree/output_rate";
size_t length = strlen(source);
char *str = malloc(1 + length);
if (str == NULL)
return -1;
strcpy(str, source);
insert(&str, '-', 8);
insert(&str, '2', 9);
printf("%s\n", str);
free(str);
return 0;
}

first of all thist char c = "a" should be replace with this char c = 'a'; because c is a character not a string
as for your problem I didn't realy see the relation between what your code is doing with what you said you wanted to do , but here a piece of code to achieve what , I think , you want to do :
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void append(char* str , char c)
{
char firststr[60];
char therest[30];
strcpy(firststr , strtok(str , "/"));
strcpy(therest , strtok(NULL , "/"));
strcat(firststr , &c);
strcat(firststr , "/");
strcat(firststr , therest);
strcpy(str , firststr);
}
int main(void)
{
char str[60] = "qos-tree/output_rate";
char c = '2';
append(str , c);
printf("%s\n" , str);
}
there you go I think this is what you wanted to do you can modify the array sizes to fit your needs

Related

Why my returned value of strchr is ignored?

I have to make a function, that will code my sentence like this: I want to code all words with an o, so for example I love ice cream becomes I **** ice cream.
But my function ignores the result of strchr. And I don't know why.
This is my code:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define LEN 1000
char *Shift(char *str, char *let) {
const char *limits = " ,-;+.";
char copy[LEN];
strcpy(copy, str);
char *p;
char *ptr;
ptr = strtok(copy, limits);
for (int j = 0; ptr != NULL; ptr = strtok(NULL, limits), ++j) {
int len = 0;
if (strchr(ptr, let) != NULL) {
p = strstr(str, ptr);
for (int i = 0; i < strlen(ptr); i++) {
p[i] = "*";
}
}
}
return str;
}
int main() {
char *s = Shift("I love my cocktail", "o");
puts(s);
}
Expected output is: I **** my ********
but I've got just printed the original string
For starters the function strchr is declared like
char *strchr(const char *s, int c);
that is its second parameter has the type int and the expected argument must represent a character. While you are calling the function passing an object of the type char * that results in undefined behavior
if (strchr(ptr, let) != NULL) {
It seems you mean
if (strchr(ptr, *let) != NULL) {
Also you may not change a string literal. Any attempt to change a string literal results in undefined behavior and this code snippet
p = strstr(str, ptr);
for (int i = 0; i < strlen(ptr); i++) {
p[i] = "*";
}
tries to change the string literal passed to the function
char *s = Shift("I love my cocktail", "o");
And moreover in this statement
p[i] = "*";
you are trying to assign a pointer of the type char * to a character. At least you should write
p[i] = '*';
If you want to change an original string you need to store it in an array and pass to the function the array instead of a string literal. For example
char s[] = "I love my cocktail";
puts( Shift( s, "o" ) );
Pay attention to that there is no great sense to declare the second parameter as having the type char *. Declare its type as char.
Also the function name Shift is confusing. You could name it for example like Hide or something else.
Here is a demonstration program.
#include <stdio.h>
#include <string.h>
char * Hide( char *s, char c )
{
const char *delim = " ,-;+.";
for ( char *p = s += strspn( s, delim ); *p; p += strspn( p, delim ) )
{
char *q = p;
p += strcspn( p, delim );
char *tmp = q;
while ( tmp != p && *tmp != c ) ++tmp;
if ( tmp != p )
{
for ( ; q != p; ++q ) *q = '*';
}
}
return s;
}
int main( void )
{
char s[] = "I love my cocktail";
puts(s);
puts( Hide( s, 'o' ) );
}
The program output is
I love my cocktail
I **** my ********
The for loop
for ( ; q != p; ++q ) *q = '*';
within the function can be rewritten as a call of memset
memset( q, '*', p - q );
There are multiple problems:
copying the string to a fixed length local array char copy[LEN] will cause undefined behavior if the string is longer than LEN-1. You should allocate memory from the heap instead.
you work on a copy of the string to use strtok to split the words, but you do not use the correct method to identify the parts of the original string to patch.
you should pass a character to strchr(), not a string.
patching the string with p[i] = "*" does not work: the address of the string literal "*" is converted to a char and stored into p[i]... this conversion is meaningless: you should use p[i] = '*' instead.
attempting to modify a string literal has undefined behavior anyway. You should define a modifiable array in main and pass the to Shift.
Here is a corrected version:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *Shift(char *str, char letter) {
const char *limits = " ,-;+.";
char *copy = strdup(str);
char *ptr = strtok(copy, limits);
while (ptr != NULL) {
if (strchr(ptr, letter)) {
while (*ptr != '\0') {
str[ptr - copy] = '*';
ptr++;
}
}
ptr = strtok(NULL, limits);
}
free(copy);
return str;
}
int main() {
char s[] = "I love my cocktail";
puts(Shift(s, 'o'));
return 0;
}
The above code still has undefined behavior if the memory cannot be allocated. Here is a modified version that operates in place to avoid this problem:
#include <ctype.h>
#include <stdio.h>
#include <string.h>
char *Shift(char *str, char letter) {
char *ptr = str;
while ((ptr = strchr(ptr, letter)) != NULL) {
char *p = ptr;
while (p > str && isalpha((unsigned char)p[-1]))
*--p = '*';
while (isalpha((unsigned char)*ptr)
*ptr++ = '*';
}
return str;
}
int main() {
char s[] = "I love my cocktail";
puts(Shift(s, 'o'));
return 0;
}
Note that you can also search for multiple characters at a time use strcspn():
#include <ctype.h>
#include <stdio.h>
#include <string.h>
char *Shift(char *str, const char *letters) {
char *ptr = str;
while (*(ptr += strcspn(ptr, letters)) != '\0') {
char *p = str;
while (p > str && isalpha((unsigned char)p[-1]))
*--p = '*';
while (isalpha((unsigned char)*ptr)
*ptr++ = '*';
}
return str;
}
int main() {
char s[] = "I love my Xtabentun cocktail";
puts(Shift(s, "oOxX"));
return 0;
}

String replacement not working when input string made with snprintf

I am attempting to substitute parts of a string with keywords in C however when trying to make the string and passing it to the replace_str function it is not producing an output with any replacements whilst making it a static string allows the code to function.
//C default libraries
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *replace_str(char *str, char *orig, char *rep) //from https://www.linuxquestions.org/questions/programming-9/replace-a-substring-with-another-string-in-c-170076/
{
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;
}
char* expanded(char *line)
{
char *keywords[] = { "online","blog" };
char *retval = "";
//char *buf = "[1]";
char buf[12];
for (int i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++)
{
snprintf(buf, 12, "[%d]", i);
retval = replace_str(line, buf, keywords[i]);
}
return retval;
}
int main()
{
char str[100];
gets(str);
printf(expanded(str));
getchar();
return 0;
}
When entering 'America[0]' I would expect 'Americaonline' to be returned however I only get America[0] back.

String copy using Pointer gives Issue

Here two prgrams present. Program 1 and program 2.
Input to both programs: {(0,0),(25,25)}
Output is : (0,0),(25,25)
The program -1 is working fine, giving out put as expected. Program 2 is not giving out put as expected bot no errors.
Suspecting problem at *str2 = *token in program -2.But what the problem is not identified exactly. can any one explain me
Program --1
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
char* fun_call(char [], int );
int main()
{
char str[] = "{(0,0),(25,25)}";
int base_str_leng;
char *retun_ptr;
base_str_leng = sizeof(str)-1;
printf("base_str_lemg:%d\n",base_str_leng);
retun_ptr = fun_call(str, base_str_leng);
printf("str2 in main loop:::%s\n",retun_ptr);
return 0;
}
char* fun_call(char str1[], int len)
{
printf("len::%d\n", len);
len = len-2;
printf("len=%d\n",len);
char *token = str1;
char *str2 = (char*) malloc( len * sizeof(char) );
printf("sizeof(str2) = %zd\n",malloc_usable_size(str2));
printf("token:%s\n", token);
printf("****While loop started****\n");
int i=0,j=0;
while(token[i] != '\0')
{
if(token[i] != '{' && token[i] != '}' )
{
printf("Each token:%c\n", token[i]);
str2[j] = token[i];
i++;
j++;
printf("str2_Token::%c\n", str2[j]);
}
else
{
i++;
}
}
printf("Function str2::%s\n", str2);
return (str2);
}
Program: 2
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
char* fun_call(char [], int );
int main()
{
char str[] = "{(0,0),(25,25)}";
int base_str_leng;
char *retun_ptr;
base_str_leng = sizeof(str)-1;
printf("base_str_lemg:%d\n",base_str_leng);
retun_ptr = fun_call(str, base_str_leng);
printf("str2 in main loop:::%s\n",retun_ptr);
return 0;
}
char* fun_call(char str1[], int len)
{
printf("len::%d\n", len);
len = len-2;
printf("len=%d\n",len);
char *token = str1;
char *str2 = (char*) malloc( len * sizeof(char) );
printf("sizeof(str2) = %zd\n",malloc_usable_size(str2));
printf("token:%s\n", token);
printf("****While loop started****\n");
while(*token != '\0')
{
if(*token != '{' && *token != '}' )
{
// printf("Each token:%c\n", token[i]);
*str2 = *token;
str2++;
token++;
// printf("str2_Token::%c\n",*str2);
}
else
{
token++;
}
}
printf("Function str2::%s\n", str2);
return (str2);
}
In your program 2 you do not end the string with \0, your while loop ends when token[i] == '\0'
You could use calloc instead to initialize the memory to 0
char *str2 = calloc( len, sizeof(char) );

Output not as expected

I am supposed to write a program to extract Web addresses starting with www. and ending with .edu. The program displays Web address contained in the input entered by the user. If the input does not contain a web address that starts with www. and ends with .edu, the program should display a message that indicates such a web address cannot be found.
Input: http://www.usf.edu/admission
Output: www.usf.edu
Input: https://www.facebook.com/
Output: Web address starting with www. and ending with .edu not found
However when my program runs, it is not displaying the correct output. I don't have any compiler errors or warnings so I'm not sure where the issue could be.
// This program extracts the text from the website URL
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define STR_LEN 1000
void read_line(char *str, int n);
void pass_check(char *str);
void extract(char *s1, char *s2);
int main(void)
{
char instr[STR_LEN + 1];
char outstr[STR_LEN + 1];
printf("Please enter a URL: ");
read_line(instr, STR_LEN);
extract(instr, outstr);
puts(outstr);
pass_check(outstr);
return 0;
}
void extract(char *s1, char *s2) {
char *p, *q;
q = s2;
for (p = s1 + 7; *p != 0; p++) {
if (*p == '/')
break;
else {
*q = *p;
q++;
}
}
*q = '\0';
*p = '\0';
}
void read_line(char *str, int n) {
int ch;
int i = 0;
while ((ch = getchar()) != '\n') {
if (i < n) {
*str++ = ch;
i++;
}
}
*str = '\0';
}
void pass_check(char *str) {
const char *fref = "www";
const char *lref = "edu";
int len = strlen(str);
printf("%d", len);
char *l = &str[len - 3];
char f[STR_LEN + 1];
strncpy(f, str, 3);
if ((strcmp(f, fref) == 0) && strcmp(l, lref) == 0) {
printf("Output: ");
puts(str);
printf("\n");
} else
printf("Please only insert a .edu URL.");
}
The function strncpy() does not do what you think it does: strncpy(f, str, 3); will not append a null byte to f, so strcmp(f, fref); will actually have undefined behavior as f is uninitialized beyond the first 3 bytes.
Do not use this function, learn why from these blogs:
https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/
https://blog.liw.fi/posts/strncpy/
Also note that your readline() function will run an infinite loop is the file is empty or not terminated by a newline.
Here is a corrected version:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define STR_LEN 1000
void read_line(char *str, size_t n);
int extract(const char *str, char *dest);
int main(void) {
char instr[STR_LEN + 1];
char outstr[STR_LEN + 1];
printf("Please enter a URL: ");
read_line(instr, sizeof(instr));
if (extract(instr, outstr)) {
puts(outstr);
} else {
printf("Web address starting with www. and ending with .edu not found\n");
}
return 0;
}
int read_line(char *str, size size) {
int ch;
size_t i = 0;
while ((ch = getchar()) != EOF && c != '\n') {
if (i + 1 < size) {
str[i++] = ch;
}
}
str[i] = '\0';
return (ch == EOF && i == 0) ? EOF : i;
}
int extact(const char *str, char *dest) {
const char *p;
*dest = '\0';
for (;;) {
if ((p = strstr(str, "https://www.")) != NULL) {
p += 8; // skip the https:// prefix
} else
if ((p = strstr(str, "http://www.")) != NULL) {
p += 7; // skip the http:// prefix
} else {
break;
}
// URL starts with www.
size_t len = strcspn(p, "/ \n"); // compute length of website name
if (len > 8 && !memcmp(p + len - 4, ".edu", 4)) {
// copy website name, assuming dest is at least as large as str
strncat(dest, p, len);
return 1;
}
str = p + len;
}
return 0;
}

Using strtok in c

I need to use strtok to read in a first and last name and seperate it. How can I store the names where I can use them idependently in two seperate char arrays?
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="test string.";
char * test;
test = strtok (str," ");
while (test != NULL)
{
printf ("%s\n",test);
test= strtok (NULL, " ");
}
return 0;
}
Here is my take at a reasonably simple tokenize helper that
stores results in a dynamically growing array
null-terminating the array
keeps the input string safe (strtok modifies the input string, which is undefined behaviour on a literal char[], at least I think in C99)
To make the code re-entrant, use the non-standard strtok_r
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char** tokenize(const char* input)
{
char* str = strdup(input);
int count = 0;
int capacity = 10;
char** result = malloc(capacity*sizeof(*result));
char* tok=strtok(str," ");
while(1)
{
if (count >= capacity)
result = realloc(result, (capacity*=2)*sizeof(*result));
result[count++] = tok? strdup(tok) : tok;
if (!tok) break;
tok=strtok(NULL," ");
}
free(str);
return result;
}
int main ()
{
char** tokens = tokenize("test string.");
char** it;
for(it=tokens; it && *it; ++it)
{
printf("%s\n", *it);
free(*it);
}
free(tokens);
return 0;
}
Here is a strtok-free reimplementation of that (uses strpbrk instead):
char** tokenize(const char* str)
{
int count = 0;
int capacity = 10;
char** result = malloc(capacity*sizeof(*result));
const char* e=str;
if (e) do
{
const char* s=e;
e=strpbrk(s," ");
if (count >= capacity)
result = realloc(result, (capacity*=2)*sizeof(*result));
result[count++] = e? strndup(s, e-s) : strdup(s);
} while (e && *(++e));
if (count >= capacity)
result = realloc(result, (capacity+=1)*sizeof(*result));
result[count++] = 0;
return result;
}
Do you need to store them separately? Two pointers into a modified char array will yield two separate perfectly usable strings.
That is we transform this:
char str[] ="test string.";
Into this:
char str[] ="test\0string.";
^ ^
| |
char *s1 ----- |
char *s2 -----------
.
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="test string.";
char *firstname = strtok(str, " ");
char *lastname = strtok(NULL, " ");
if (!lastname)
lastname = "";
printf("%s, %s\n", lastname, firstname);
return 0;
}
What about using strcpy:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAX_NAMES 2
int main ()
{
char str[] ="test string.";
char *names[MAX_NAMES] = { 0 };
char *test;
int i = 0;
test = strtok (str," ");
while (test != NULL && i < MAX_NAMES)
{
names[i] = malloc(strlen(test)+1);
strcpy(names[i++], test);
test = strtok (NULL, " ");
}
for(i=0; i<MAX_NAMES; ++i)
{
if(names[i])
{
puts(names[i]);
free(names[i]);
names[i] = 0;
}
}
return 0;
}
It contains much clutter to maintain a complete program and clean its resources, but the main point is to use strcpy to copy each token into its own string.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char** split(const char *str, const char *delimiter, size_t *len){
char *text, *p, *first, **array;
int c;
char** ret;
*len = 0;
text=strdup(str);
if(text==NULL) return NULL;
for(c=0,p=text;NULL!=(p=strtok(p, delimiter));p=NULL, c++)//count item
if(c==0) first=p; //first token top
ret=(char**)malloc(sizeof(char*)*c+1);//+1 for NULL
if(ret==NULL){
free(text);
return NULL;
}
strcpy(text, str+(first-text));//skip until top token
array=ret;
for(p=text;NULL!=(p=strtok(p, delimiter));p=NULL){
*array++=p;
}
*array=NULL;
*len=c;
return ret;
}
void free4split(char** sa){
char **array=sa;
if(sa!=NULL){
free(array[0]);//for text
free(sa); //for array
}
}
int main(void){
char str[] ="test string.";
char **words;
size_t len=0;
int i;
words = split(str, " \t\r\n,.", &len);
/*
for(char **wk = words; *wk ;wk++){
printf("%s\n", *wk);
}
*/
for(i = 0;i<len;++i){
printf("%s\n", words[i]);
}
free4split(words);
return 0;
}
/* result:
test
string
*/
Copy the results from strtok to a new buffer using a function such as
/*
* Returns a copy of s in freshly allocated memory.
* Exits the process if memory allocation fails.
*/
char *xstrdup(char const *s)
{
char *p = malloc(strlen(s) + 1);
if (p == NULL) {
perror("memory allocation failed");
exit(1);
}
strcpy(p, s);
return p;
}
Don't forget to free the return values when you're done with them.
IMO, you don't need (and probably don't want) to use strtok at all (as in, "for this, or much of anything else"). I think I'd use code something like this:
#include <string.h>
#include <stdlib.h>
static char *make_str(char const *begin, char const *end) {
size_t len = end-begin;
char *ret = malloc(len+1);
if (ret != NULL) {
memcpy(ret, begin, len);
ret[len]='\0';
}
return ret;
}
size_t tokenize(char *tokens[], size_t max, char const *input, char const *delims) {
int i;
char const *start=input, *end=start;
for (i=0; *start && i<max; i++) {
for ( ;NULL!=strchr(delims, *start); ++start)
;
for (end=start; *end && NULL==strchr(delims, *end); ++end)
;
tokens[i] = make_str(start, end);
start = end+1;
}
return i;
}
#ifdef TEST
#define MAX_TOKENS 10
int main() {
char *tokens[MAX_TOKENS];
int i;
size_t num = tokenize(tokens, MAX_TOKENS, "This is a longer input string ", " ");
for (i=0; i<num; i++) {
printf("|%s|\n", tokens[i]);
free(tokens[i]);
}
return 0;
}
#endif
U can do something like this too.
int main ()
{
char str[] ="test string.";
char * temp1;
char * temp2;
temp1 = strtok (str," ");
temp2 = strchr(str, ' ');
if (temp2 != NULL)
temp2++;
printf ("Splitted string :%s, %s\n" , temp1 , temp2);
return
}

Resources