Construct String in C - c

Here is the demo code I am using to construct string from char arrays, Is there any better way to construct String *RV200# *FV200# ??
int main()
{
char String4H1[10] = "*FV";
char String4H3[10] = "*RV";
char String4H2[10] = "#";
char data1[10];
char data2[10];
snprintf(data1,4, "%03d", 200); //Convert integer to string function
snprintf(data2,4, "%03d", 200); //Convert integer to string function
ConvertToString(String4H1,data1, 3); //*FV200
ConvertToString(String4H3,data2, 3); //*RV200
ConvertToString(String4H1,String4H2,6); //*FV200#
ConvertToString(String4H3,String4H2,6); //*RV200#
//Display String4H1 And String 4H3
}
void ConvertToString(char subject[], const char insert[], int pos)
{
char buf[100] = {};
strncpy(buf, subject, pos); // copy at most first pos characters
int len = strlen(buf);
strcpy(buf+len, insert); // copy all of insert[] at the end
len += strlen(insert); // increase the length by length of insert[]
strcpy(buf+len, subject+pos); // copy the rest
strcpy(subject, buf); // copy it back to subject
// deallocate buf[] here, if used malloc()
}
The number 200 is not known at the start of the program, it is fetched from memory using the IDE function to get value from particular memory address.
like this :-
unsigned short BUF = GetWord(#FrontVIB#,0);
unsigned short BUF1 = GetWord(#RearVIB#,0);
//BUF and BUF1 stores the value of address #FrontVIB# and #RearVIB# respectively
**structure** :-
unsigned short GetWord( #Address Alias#, Address Offset );

That's a simple example. Probably I'll be down-voted :)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
bool concatenateString(char **dest, size_t *size, char *stringToAdd)
{
bool retVal = true;
char *dest_old = *dest;
*size += strlen(stringToAdd);
if (*dest == NULL)
{
*size += 1; // to add null terminator of string
*dest = calloc(1, size);
}
else
{
*dest = realloc(*dest, size);
}
if (dest == NULL)
{
free(dest_old);
retVal = false;
}
else
{
strcat(*dest, stringToAdd);
}
return retVal;
}
int main()
{
char newString[32] = {0};
int number;
size_t size = 0;
char *data1 = NULL;
printf("Insert a string:");
scanf(" %s", newString);
if (concatenateString(&data1, &size, newString))
{
printf("Insert a number:");
scanf(" %d", &number);
sprintf(newString, "%03d", number);
if (concatenateString(&data1, &size, newString) )
{
printf("Insert a string:");
scanf(" %s", newString);
if (concatenateString(&data1, &size, newString))
printf("%s\n", data1);
}
}
free(data1);
}
Without using dynamic allocation
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
bool concatenateString(char *dest, size_t size_of_dest, char *stringToAdd)
{
bool retVal = true;
size_t new_size = strlen(dest) + strlen(stringToAdd);
if (new_size < size_of_dest)
{
strcat(dest, stringToAdd);
}
else
{
retVal = false;
}
return retVal;
}
int main()
{
char result[128] = {0};
char newString[32] = {0};
int number;
printf("Insert a string:");
scanf(" %s", newString);
printf("%s\n", newString);
if (concatenateString(result, sizeof(result), newString))
{
printf("Insert a number:");
scanf(" %d", &number);
sprintf(newString, "%03d", number);
if (concatenateString(result, sizeof(result), newString) )
{
printf("Insert a string:");
scanf(" %s", newString);
if (concatenateString(result, sizeof(result), newString))
printf("%s\n", result);
}
}
}
INPUT
Insert a string: *RV
Insert a number: 200
Insert a string: #
OUTPUT
*RV200#

A number of issues, I am only tackling ConvertToString()
Although some attempts made at coping with string buffer issues, too many holes exist in OP's code. Consider the following.
void ConvertToString(char subject[], const char insert[], int pos) {
char buf[100] = {};
strncpy(buf, subject, pos); // copy at most first pos characters
int len = strlen(buf);
...
What is the impact of pos == 100?
strlen(buf) may attempt to find the length of a character array with no null character --> UB.
What is the impact of pos > 100?
strncpy() attempts to write data outside the bonds of buf.
Pedantic: What is the impact of pos < 0?
strncpy() attempts to write data outside the bonds of buf as pos is converted into an excessive large unsigned number.
Concerning strcpy(buf+len, subject+pos);
What is the impact if pos exceeds strlen(subject)
UB as code attempts to read outside subject.
Re-write attempt. The key elements: include the size available for the expanded subject is passed in and determine string lengths. Then test for acceptability. After all that, shift the end of subject to make room for insert.
void ConvertToString(char subject[], size_t subject_size, const char *insert,
size_t pos) {
size_t insert_length = strlen(insert);
size_t subject_length = strlen(subject);
// Insure pos does not exceed subject_length,
// this critical part missing in OP code
if (pos > subject_length) {
pos = subject_length;
}
// Insure we have enough space
size_t buf_size = subject_length + insert_length + 1;
if (buf_size > subject_size) {
Handle_Insufficent_subject_size();
return;
}
// Move end portion of `subject` over to the right `insert_length` places.
memmove(subject + pos + insert_length, subject + pos, subject_length - pos + 1);
memcpy(subject + pos, insert, insert_length); // copy insert
}

Related

C program that replace word in sentence to another word

I tried to replace a target word in sentence to another word but it doesn't work. Can you please help me with where I got wrong? It has a problem with strstr and strncopy. It says that *swap can be zero, which then makes strncpy stop. I tried to find way to solve this problem, but I couldn't. How can I fix this code?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *swap (char* data, const char* original, const char* change);
int main() {
char string[100];
char original[100];
char change[100];
printf("Input String : ");
fgets(string, 100, stdin);
printf("Find String : ");
fgets(original, 100, stdin);
printf("Replace String : ");
fgets(change, 100, stdin);
printf("%s", swap(string, change, original));
return 0;
}
char *swap(char* data, const char* original, const char* change) {
char* swap;
swap = strstr(data, original);
int num = strlen(change);
if (num == 0 || swap==0) return 0;
strncpy(swap, change, strlen(change));
printf("Result : %s", data);
return 0;
}
I have fixed your code and added a few tests to avoid buffer overflow vulnerability in your swap function.
My version take car of change and original being of different lengths.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *swap(char* data, int size, const char* original, const char* change);
int main()
{
char string[100];
char original[100];
char change[100];
printf("Input String : ");
fgets(string, sizeof(string), stdin);
string[strcspn(string, "\r\n")] = 0; // Remove EOL
printf("Find String : ");
fgets(original, sizeof(original), stdin);
original[strcspn(original, "\r\n")] = 0; // Remove EOL
printf("Replace String : ");
fgets(change, sizeof(change), stdin);
change[strcspn(change, "\r\n")] = 0; // Remove EOL
printf("%s\n", swap(string, sizeof(string), original, change));
return 0;
}
char *swap(char* data, int size, const char* original, const char* change)
{
if ((data == NULL) || (original == NULL) || (change == NULL))
return data; // Unspecified data
int datLen = strlen(data);
int oriLen = strlen(original);
if (oriLen == 0)
return data; // No original specified
char *swap = strstr(data, original);
if (swap == NULL)
return data; // Original not found in data
int chgLen = strlen(change);
if (size < (datLen + chgLen - oriLen))
return data; // Not enough space to store result
if (chgLen != oriLen)
memmove(swap + chgLen, swap + oriLen, 1 + datLen + oriLen - (swap - data));
memmove(swap, change, chgLen);
return data;
}
I have not changed that, but I think it is better to have swap return 0 or 1 if the swap took place or not. Returning data is not very useful as the swap is done in place.

I cant solve chaning characters

Required use of the function that returns the length of the string.
Write a function that receives two character chains (n1, n2). The function of the function is to check if the string n2 is the subscription of the string n1. The function returns the index of the first occurrence of the string n2 in the string n1 (if n2 is the string n1) or -1 (if n2 is not the string n1). assumption: the inscription n2 is shorter than the inscription n1.
Example: inscription n1: "Computer" inscription n2: "er" Function returns: 6
i did it and it work
#include <stdio.h>
#define LIMIT 50
char * string_in(char *string, char *substring);
char * get(char *string, int n);
int main(void)
{
// test string_in()
char string[LIMIT];
char substring[LIMIT];
char *substr_loc;
printf("Enter a string: ");
get(string, LIMIT);
while (string[0] != '\0')
{
printf("Enter a substring to look for: ");
get(substring, LIMIT);
substr_loc = string_in(string, substring);
if (substr_loc == NULL)
printf("%s not in %s\n", substring, string);
else
printf("%s found in %s at index %lu\n",
substring, string, substr_loc - string);
printf("Enter a string (empty line to quit): ");
get(string, LIMIT);
}
puts("Bye");
return 0;
}
char * string_in(char *string, char *substring)
{
// checks if substring is in string
// returns pointer to first location of substring
// in string or NULL if substring not in string
int i;
while (*string != '\0')
{
i = 0;
// check for substring at current location
while (*(string + i) == *(substring + i))
{
i++;
// if next char in substring is null, then match
// is found. return current location
if (*(substring + i) == '\0')
return string;
}
string++;
}
// no match
return NULL;
}
char * get(char *string, int n)
{
// wrapper for fgets that replaces first newline with null
char *return_value = fgets(string, n, stdin);
while (*string != '\0')
{
if (*string == '\n')
{
*string = '\0';
break;
}
string++;
}
return return_value;
}
the next step is
Write a part of the program that will replace all occurrences of the n2 string in the string n1 with the string (the character '*'). Use the function from a task point. Please tell me how to write this function
Example: n1: "Spectacle" n2: "c" string n1 after change. "Spe*ta*le"
void function(char * get, char * string_in)
int i = 0;
for ( i = 0; get[i]=!'\0';i++){
if (get[i] == string_in[o]
get[i] = '*';}
dont work;<
it is a bit more complicated if you the string which replaces another string is longer. Here you have simple functions.
size_t strstrIndex(const char *heap, const char *needle) // returns SIZE_MAX if not found
{
char *result = strstr(heap,needle);
return result ? result - heap : SIZE_MAX;
}
char *replace(const char *heap, const char *needle, const char *rep)
{
size_t pos = 0, nocc = 0;
size_t len = strlen(heap), nlen = strlen(needle), rlen = strlen(rep);
char *string;
char *wstr = (char *)heap;
while((pos = strstrIndex(wstr, needle)) != SIZE_MAX)
{
nocc++;
wstr += pos + nlen;
}
string = calloc(1, len + ((rlen > nlen) ? (rlen - nlen) * nocc : 0) + 1);
if(string)
{
wstr = string;
while((pos = strstrIndex(heap, needle)) != SIZE_MAX)
{
strncpy(wstr, heap, pos);
heap += pos + nlen;
wstr += pos;
strcpy(wstr, rep);
wstr += rlen;
}
if(*heap)
{
strcpy(wstr, heap);
}
}
return string;
}
int main()
{
char *heap = "Spectaclec";
printf("%s\n", replace(heap, "c", "*"));
printf("%s\n", replace(heap, "c", "*****"));
printf("%s\n", replace("ccSpecctaccleccX", "cc", "*****"));
}
This task is easy if you use the functions that comes with the C library:
void ReplaceString(char *pTarget, const char *pPattern)
{
char *p;
size_t PatternLength = strlen(pPattern);
// for all occurances of the pattern..
while (p = strstr(pTarget, pPattern))
{
// The function strstr found an occurance of the pattern.
// So it must be sufficient space in the target starting at the pointer p..
// replace the characters in the target
memset(p, '*', PatternLength);
}
}
If you should avoid functions for some academic purposes, you can implement your own versions of strlen, strstr, and memset. Your example shows a function string_in that looks like such version of `strstr.

Get string until first digit

I need to get all the characters before the first digit from an array.
I did this and it seems to work correctly:
#include <stdio.h>
int main() {
char temp[128] = {0};
char str_active[128] = {0};
sprintf(temp, "%s", "AB01");
printf("Complete string.: %s\n", temp);
int len = sizeof(temp) / sizeof(char);
int index = 0;
while (index < len) {
if (isdigit(temp[index])) {
break;
} else {
index++;
}
}
snprintf(str_active, index + 1, "%s\n", temp);
printf("String before first digit.: %s\n", str_active);
return 0;
}
I'm wondering if I could do the same with less instructions, so in a better way.
The function strcspn can do it for you:
The strcspn() function calculates the length of the initial segment of s which consists entirely of bytes not in reject.
#include <stdio.h>
#include <string.h>
int main() {
char temp[128] = {0};
char str_active[128] = {0};
sprintf(temp, "%s", "AB01");
printf("Complete string.: %s\n", temp);
strncpy(str_active, temp, strcspn(temp, "0123456789"));
printf("String before first digit.: %s\n", str_active);
return 0;
}

Appending two strings

I'm trying to write code to append two strings without the function strcat, but it doesn't work. It only works when the inputs are a single char.
Here's the code:
#include <stdio.h>
#include <string.h>
/*
Return the result of appending the characters in s2 to s1.
Assumption: enough space has been allocated for s1 to store the extra
characters.
*/
char* append (char s1[], char s2[]) {
int s1len = strlen (s1);
int s2len = strlen (s2);
int k;
for (k=0; k<s2len; k++) {
s1[k+s1len] = s2[k];
}
return s1;
}
int main ( ) {
char str1[10];
char str2[10];
while (1) {
printf ("str1 = ");
if (!gets(str1)) {
return 0;
};
printf ("str2 = ");
if (!gets(str2)) {
return 0;
};
printf ("The result of appending str2 to str1 is %s.\n",
append (str1, str2));
}
return 0;
}
How can I fix it?
You have some errors in your code:
Do not use gets. This function is dangerous because it doesn't take the
size of the buffer into account. Use fgets instead.
Your append function does not write the '\0'-terminating byte. It should
be
char* append (char s1[], char s2[]) {
int s1len = strlen (s1);
int s2len = strlen (s2);
int k;
for (k=0; k<s2len; k++) {
s1[k+s1len] = s2[k];
}
s1[k+s1len] = 0; // writing the 0-terminating byte
return s1;
}
str1 may be to short for holding both strings. If str2 contains "Hello"
and str2 contains "World!", you are going to overflow the buffer. Make the
buffer larger.
If you writing your own strcat, I would pass the size of the destination
buffer as well, so that you don't overflow the buffers:
char *mystrcat(char *t1, const char *t2, size_t maxsize)
{
if(t1 == NULL || t2 == NULL)
return NULL;
size_t s1 = strlen(t1);
size_t s2 = strlen(t2);
size_t i;
for(i = 0; i < s2 && (s1 + i) < maxsize - 1 ; ++i)
t1[i + s1] = t2[i];
t1[i + s1] = 0; // terminating the
return t1;
}
int main(void)
{
char str1[30] = "Hello ";
char str2[30] = "World!";
printf("mystrcat(\"%s\", \"%s\") = %s\n", str1, str2,
mystrcat(str1, str2, sizeof str1));
char str3[100] = "This is a long sentence";
printf("mystrcat(\"%s\", \"%s\") = %s\n", str1, str3,
mystrcat(str1, str3, sizeof str1));
char line[100];
printf("Enter some text: ");
fflush(stdout);
fgets(line, sizeof line, stdin);
line[strcspn(line, "\n")] = 0; // removing possible newline
strcpy(str3, "User input was: ");
printf("mystrcat: %s\n", mystrcat(str3, line, sizeof str3));
return 0;
}
That would return
mystrcat("Hello World!", "World!") = Hello World!
mystrcat("Hello World!This is a long se", "This is a long sentence") = Hello World!This is a long se
Enter some text: ABC DEF user input is great
mystrcat: User input was: ABC DEF user input is great
Your resulting string is not properly terminated.
Strings in C are always terminated with a NUL (0) character.
gets is unsafe, use fgets instead.
Get in the habit to check buffer sizes.
To give you an idea, here a minimalistic implementation using fgets + buffer size checks:
#include <stdio.h> // fprintf, fgets
#include <string.h> // strlen
const char *concatenate(char *dst, size_t sz, const char *s1, const char *s2) {
size_t l1 = strlen(s1);
size_t l2 = strlen(s2);
// Check for overflow
if ((l1 + l2 + 1) > sz) {
return NULL;
}
// Copy first string
for (size_t i = 0; i < l1; ++i) {
dst[i] = s1[i];
}
// Copy second string
for (size_t i = 0; i < l2; ++i) {
dst[l1 + i] = s2[i];
}
// Add NUL terminator
dst[l1 + l2 + 1] = 0;
return dst;
}
int main() {
// Allocate two strings (9 chars max.)
char first_string[10];
char second_string[10];
char concatenated_string[20];
// Read first string from stdin
fprintf(stdout, "str1 = ");
// !!! fgets return value check omitted for simplicity.
fgets(first_string, sizeof(first_string), stdin);
// Read second string from stdin
fprintf(stdout, "str2 = ");
// !!! fgets return value check omitted for simplicity.
fgets(second_string, sizeof(second_string), stdin);
const char *tmp = concatenate(concatenated_string, sizeof(concatenated_string), first_string, second_string);
if (!tmp) {
fprintf(stderr, "would overflow\n");
} else {
fprintf(stdout, "concatenated: %s\n", concatenated_string);
}
return 0;
}

Unique Words Counter in C

I'm programming a little programm in C wich should count unique words in c.
To do this, i'm having an wordbook to store all found words. Normaly it should only put words inside that aren't already in it but it keeps entering all writen words.
How can i fix this and how can i delete all the empty parts in my wordbook "woerterbuch" ?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char lies_wort(char *Text);
char suche_wort(char *wort);
char neues_wort(char *wort);
char *woerterbuch[1000];
int main(void)
{
char Text[1000];
printf("Bitte Text eingeben : \n") ;
fgets (Text, 1000, stdin);
lies_wort(Text);
int i;
for(i=0;i<1000;i++){
printf("woerterbuch :%s\n",woerterbuch[i]);}
}
char lies_wort(char *Text){
char *wort;
int i=1;
wort = strtok(Text, " ,.!?;:");
while(wort != NULL) {
suche_wort(wort);
printf("gefunden %d: %s\n", i++, wort);
wort = strtok(NULL, " ,.!?;:");}
}
char suche_wort(char *wort)
{
int i;
for (i = 0; i>1000; i++){
if (!strcmp(woerterbuch[i],wort)){return 0;}}
neues_wort(wort);
return 0;
}
char neues_wort(char *wort)
{
int i;
for (i=0; i<1000; i++){
if(woerterbuch[i]==0){
woerterbuch[i]=wort;
return 0;}}
}
For Testing this programm is just printing all words in "woerterbuch" so i can check if it's working.
In suche_wort
for (i = 0; i>1000; i++)
It should be
for (i = 0; i<1000; i++)
Your loop is terminating right away everytime.
I believe you have some issues in your code:
Firstly, in this line:
woerterbuch[i]=wort;
Will only overwrite the address of woerterbuch[i], and this will lead to wrong results. Instead you need to allocate space for worterbuch[i], via malloc or strdup.
You can use allocate space for a single pointer like this:
worterbuch[i] = malloc(strlen(wort)+1);
Note: It is always good to check the return from malloc(), and free() these pointers at the end.
Now, since the pointer is pointing somewhere, you can copy stuff into it. You can use strcpy to do this. If you want to skip this copy step, you can just use strdup() instead.
Secondly, instead of globally defining char *woerterbuch[1000];, you can manage this array of pointers in a struct:
typedef struct {
char *woerterbuch[1000];
size_t n;
} worterbuch;
Which will make it easier to manage your array.
Thirdly, you are not checking the return of fgets(). This can return NULL if unsuccessful. You should also check for buffer overflow here.
Lastly, if their are a lot of words in your worterbuch, it might not be efficient to use linear search to check for duplicates. This process is O(N) time on average. Instead, you can use binary search, which is O(logN) on average, therefore much more efficient if n becomes very large.
Here is some code I wrote a while ago which does something similar:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TEXTSIZE 1000
typedef struct {
char *dictionary[TEXTSIZE];
size_t numwords;
} dictionary_t;
void read_text(char *text);
void read_words(char *text, dictionary_t *dict);
int search_word(dictionary_t *dict, char *word);
void print_words(dictionary_t *dict);
int str_cmp(const void *a, const void *b);
int main(void) {
dictionary_t dict;
char text[TEXTSIZE];
read_text(text);
read_words(text, &dict);
print_words(&dict);
return 0;
}
void read_text(char *text) {
size_t slen;
printf("Please enter text: \n");
if (fgets(text, TEXTSIZE, stdin) == NULL) {
fprintf(stderr, "Error reading text\n");
exit(EXIT_FAILURE);
}
/* removes '\n' character from fgets(), and checks for overflow */
slen = strlen(text);
if (slen > 0) {
if (text[slen-1] == '\n') {
text[slen-1] = '\0';
} else {
printf("Buffer overflow detected.\n");
exit(EXIT_FAILURE);
}
}
if (!*text) {
printf("No text entered.\n");
exit(EXIT_FAILURE);
}
}
void read_words(char *text, dictionary_t *dict) {
char *word;
const char *delim = " ,.!?;:";
dict->numwords = 0;
word = strtok(text, delim);
while (word != NULL) {
if (search_word(dict, word)) {
/* allocate space for ptr */
dict->dictionary[dict->numwords] = malloc(strlen(word)+1);
if (!dict->dictionary[dict->numwords]) {
printf("Cannot allocate word.\n");
exit(EXIT_FAILURE);
}
/* copy it into array */
strcpy(dict->dictionary[dict->numwords], word);
/* increment count, ready for next word */
dict->numwords++;
}
word = strtok(NULL, delim);
}
}
/* linear searching the word */
int search_word(dictionary_t *dict, char *word) {
size_t i;
for (i = 0; i < dict->numwords; i++) {
if (strcmp(dict->dictionary[i], word) == 0) {
return 0;
}
}
return 1;
}
/* cmp function for sorting dictionary */
int str_cmp(const void *a, const void *b) {
const char **str1 = (const char **)a;
const char **str2 = (const char **)b;
return strcmp(*str1, *str2);
}
void print_words(dictionary_t *dict) {
size_t i;
/* sort using qsort */
qsort(dict->dictionary, dict->numwords, sizeof(*(dict->dictionary)), str_cmp);
printf("\nDictionary:\n");
for (i = 0; i < dict->numwords; i++) {
printf("%s\n", dict->dictionary[i]);
/* freeing memory previosly allocated from malloc() */
free(dict->dictionary[i]);
dict->dictionary[i] = NULL;
}
}

Resources