I am writing a code to rearrange the words in a string from back to front. I have first managed to arranged the characters from back to front but cannot seem to reset a string to null before swapping the second word in the string a second time and so on.
For example, with the input, "What the hell is going on here"
The output turns out to be, "here onre going ising hellg thelg Whatg"
So the last letters of the previous word stay with the "tempWord" variable. How can I fix this?
void revString(char statement[]);
int main (void){
int index;
char tempWord[LENGTH];
char statement[LENGTH] = "What the hell is going on here";
const char s[2] = " ";
char *word;
int wordCounter = 0;
revString(statement);
printf("%s\n", statement); //Temp printing
(Just so it's clear, the code I'm asking about is below this line)
//////////////////////////////////////////////////////////////////////////////////////
index = 0;
word = strtok(statement, s);
while (word != NULL){
wordCounter++;
for (index = 0; index <= strlen(word); index++){
tempWord[index] = '\0';
}
strcpy(tempWord, word);
revString(tempWord);
printf("%s ", tempWord);
word = strtok(NULL, s);
}
printf("\n");
printf("%d words", wordCounter);
}
Let me know what you think!
void revString(char original[]){
int index;
char temp[LENGTH];
int j = 1;
for (index = 0; index < strlen(original); index++, j++){
temp[(strlen(original) - j)] = original[index];
}
strcpy(original, temp);
original[strlen(original)] = '\0';
}
The problem is temp is not terminated with '\0'.
I modified the revString and tweaked a bit (called strlen only once)...
void revString(char original[]){
int index;
char temp[LENGTH];
int j = 1;
int len = strlen(original);
temp[len] = '\0';
for (index = 0; index < len; index++, j++){
temp[len - j] = original[index];
}
strcpy(original, temp);
original[len] = '\0';
}
Interestingly your original code doesn't give me a problem for LENGTH values from 30 to 100. For more than 200 bytes values it gives me strange characters (possibly the garbage) which got me into setting the last character in string "temp" to NULL.
Set the terminating Null character for tempword, according to the length of word
i.e.
while (word != NULL){
wordCounter++;
strcpy(tempWord, word);
revString(tempWord);
tempWord[strlen(word)] = '\0';
printf("%s ", tempWord);
word = strtok(NULL, s);
}
printf("\n");
printf("%d words", wordCounter);
}
Related
void redact_words(const char *text_filename, const char *redact_words_filename){
FILE *fp = fopen(text_filename,"r");
FILE *f2p = fopen(redact_words_filename,"r");
FILE *f3p = fopen("result.txt", "w"); ;
char buffer1[1000];
char buffer2[1000];
char *word;
char *redact;
char **the_words;
//if ((fgets(buffer1, 1000 ,fp) == NULL) || (fgets(buffer2,1000 ,f2p) == NULL))
fgets(buffer1,1000,fp);
fgets(buffer2,1000,f2p);
rewind(fp);
rewind(f2p);
int word_count = 0;
while (!feof(f2p)){
char c = fgetc(f2p);
if (c == ' '){
word_count += 1;
}
}
word_count += 1;
the_words = malloc(3 * sizeof(char*));
redact = strtok(buffer2, ", ");
for (int i = 0; i < word_count; i++){
the_words[i] = malloc(100);
the_words[i] = redact;
redact = strtok(NULL, ", ");
}
char result[256] = "";
word = strtok(buffer1, " ");
while (word != NULL){
for (int i = 0; i < word_count; i++){
if (strcasecmp(the_words[i],word) == 0){
for (int i = 0; i < strlen(word); i++){
strcat(result,"*");
}
strcat(result, " ");
break;
}
else{
if (i==(word_count-1)){
strcat(result, word);
strcat(result, " ");
}
}
}
word = strtok(NULL," ");
}
fputs(result, f3p);
fclose(fp);
fclose(f2p);
fclose(f3p);
free(the_words);
}
So this is my C code to replace words from the file called text_filename with asterixs if the word exists in a file called redact_words_filename. However, I noticed during the comparison with the 2 strings
if (strcasecmp(the_words[i],word) == 0){
for (int i = 0; i < strlen(word); i++){
strcat(result,"*");
}
that when I have the word quick for example in both text files, the_words[i] contains a string of length 6 while the one in word contains a string of length 5, both containing the value quick, and so it is not registering as the same string. Why is one of the strings longer than another?
(P.s I apologise for the bad code quality)
Edit 1: Ok so I found out it has to do with \n which is put in at the end of every line. Trying to find a way to solve this.
Edit 2: I managed to get rid of \n through a simple for loop
for (int i = 0; i < word_count; i++){
the_words[i] = malloc(100);
the_words[i] = redact;
for (int j = 0; j < strlen(redact); j++){
if (redact[j] == '\n'){
redact[j] = '\0';
}
}
redact = strtok(NULL, ", ");
}
the_words = malloc(3 * sizeof(char*));
redact = strtok(buffer2, ", ");
for (int i = 0; i < word_count; i++){
the_words[i] = malloc(100);
the_words[i] = redact;
redact = strtok(NULL, ", ");
}
Two obvious problems just here
you allocate space for 3 pointers in the_words but then you go and put word_count words into it. So if word_count > 3, you'll overflow and get undefined behavior
for each word, you allocate 100 bytes, and then throw away that allocation, instead storing a pointer into buffer2. The buffer currently contains the word but that will change next time you read into it. You should just use the_words[i] = strdup(redact); to both allocate the right amount of memory, and copy the string into the allocated memory.
I have a program that has to count the number of duplicate characters in a string. For example "aaabcc" should return "a3b1c2" and "aaabcccc..a" should return "a3b1c4.2a1". I am currently using sprintf to concatenate the string and numbers like this: sprintf(s, "%s%c%d", s, prev, count);, where s is the string containing the result. But that causes an error since I am using "s" as an input and also as the destination. Is there some way around this?
This is my code right now:
char *s = (char *)malloc(sizeof(char) * 100);
char prev = argv[1][0];
if(isdigit(prev)!=0){
printf("%s","ERROR");
return 0;
}
int count = 1;
for(int i=1; i<strlen(argv[1]); i++){
if(isdigit(argv[1][i])!=0){
printf("%s","ERROR");
return 0;
}
//check if same as previous letter
if(prev==argv[1][i]){
count++;
}else{
//add letter and count to string
//problem
sprintf(s, "%s%c%d", s, prev, count);
count = 1;
}
//update prev
prev=argv[1][i];
}
//add it to string
//problem
sprintf(s, "%s%c%d", s, prev, count);
//check if result is smaller than input
if(strlen(s) > strlen(argv[1])){
printf("%s\n", argv[1]);
}else{
printf("%s\n", s);
}
free(s);
Use a different buffer for sprintf(), then concatenate to s with strcat().
Make sure you initialize s to an empty string after allocating it.
Instead of allocating a hard-coded size for s, allocate a string big enough for the worst case (every character repeated just once, so it's a1b1c1...).
temp can be a short, fixed-size string, since it just has to hold the length of one run.
char *s = malloc(strlen(argv[1]) * 2 + 1);
s[0] = '\0';
char temp[20];
char prev = argv[1][0];
if(isdigit(prev)!=0){
printf("%s","ERROR");
return 0;
}
int count = 1;
for(int i=1; i<strlen(argv[1]); i++){
if(isdigit(argv[1][i])!=0){
printf("%s","ERROR");
return 0;
}
//check if same as previous letter
if(prev==argv[1][i]){
count++;
}else{
//add letter and count to string
sprintf(temp, "%c%d", prev, count);
strcat(s, temp);
count = 1;
}
//update prev
prev=argv[1][i];
}
//add it to string
sprintf(temp, "%s%c%d", prev, count);
strcat(s, temp);
//check if result is smaller than input
if(strlen(s) > strlen(argv[1])){
printf("%s\n", argv[1]);
}else{
printf("%s\n", s);
}
free(s);
The advice in the comments and other answers are giving you good guidance on how manage the strings that you are dynamically allocating with malloc. But you can simplify your entire program without ever allocating a string and without using sprintf.
Consider this:
int lastChar = '\0';
int count = 0;
const char* arg = argv[1];
int isError = 0;
if (argc < 2) {
isError = 1;
}
while (*arg & !isError) { // scan argv[1] for digits
isError = isdigit(*arg);
arg++;
}
arg = argv[1]; // reset arg back to beginning of argv[1]
while (*arg && !isError) {
if (lastChar == *arg) {
count++;
}
else {
if (count > 0) {
printf("%c%d", lastChar, count);
}
lastChar = *arg;
count = 1;
}
arg++;
}
// print the last character being tracked or error message
if (isError) {
printf("ERROR");
}
else if (count > 0) {
printf("%c%d", lastChar, count);
}
printf("\n");
I want to print the length of each word in a string.
I have tried but not getting right answer. After running the code it will print the length of each word after the word instead of printing before the each word.
char str[20] = "I Love India";
int i, n, count = 0;
n = strlen(str);
for (i = 0; i <= n; i++) {
if (str[i] == ' ' || str[i] == '\0') {
printf("%d", count);
count = 0;
} else {
printf("%c", str[i]);
count++;
}
}
I except the output is 1I 4Love 5India, but the actual output is I1 Love4 India5.
You can use strtok as Some programmer dude sugested. You may want to make a copy of the original string as strtok modifies the passed string. Also strtok is not thread-safe and must be replaced with strtok_r when working with multi-threaded programs.
#include <stdio.h>
#include <stdlib.h>
/* for strtok */
#include <string.h>
int main() {
char str[20] = "I Love India";
int n;
char* tok = strtok(str, " ");
while (tok != NULL) {
n = strlen(tok);
printf("%d%s ", n, tok);
tok = strtok(NULL, " ");
}
return EXIT_SUCCESS;
}
You want to compute and print the length of each word before you print the word.
Here is a simple solution using strcspn(), a standard function that should be used more often:
#include <stdio.h>
#include <string.h>
int main() {
char str[20] = "I Love India";
char *p;
int n;
for (p = str; *p;) {
if (*p == ' ') {
putchar(*p++);
} else {
n = strcspn(p, " "); // compute the length of the word
printf("%d%.*s", n, n, p);
p += n;
}
}
printf("\n");
return 0;
}
Your approach is wrong as you print the word before the length. So you need to calculate the length first then print it and then print the word.
It could be something like:
int main(void)
{
char str[20]="I Love India";
size_t i = 0;
while(str[i])
{
if (str[i] == ' ') // consider using the isspace function instead
{
// Print the space
printf(" ");
++i;
}
else
{
size_t j = i;
size_t count = 0;
// Calculate word len
while(str[j] && str[j] != ' ')
{
++count;
++j;
}
// Print word len
printf("%zu", count);
// Print word
while(i<j)
{
printf("%c", str[i]);
++i;
}
}
}
}
The basic idea is to have two index variables for the string, i and j. The index i is at the words first character and index j is used for finding the end of the word. Once the end of word has been found, the length and the word can be printed.
This is what you want:
#include <stdio.h>
#include <string.h>
int main()
{
char str[20]="I Love India";
char buf[20];
int i,n,count=0;
n=strlen(str);
for (i=0; i <= n; i++) {
if(str[i]==' ' || str[i]=='\0'){
buf[count] = '\0';
printf("%d", count); /* Print the size of the last word */
printf("%s", buf); /* Print the buffer */
memset(buf, 0, sizeof(buf)); /* Clear the buffer */
count = 0;
} else {
buf[count] = str[i];
count++;
}
}
return 0;
}
You will want to keep a buffer of the word that is currently being counted. (buf)
Increment count each time its not a space or 0/. Then, when it is a space or a 0/, print count first, then buf. Then, we will clear buf and set count to 0, so that the variable i is still incrementing through the entire string str, but we are inserting the words into buf starting from 0.
I tried to make a function which replace every word in a text with the word shifted to right by 'k' times.
the code look like this:
void operation_3(char *string, int k){
int len = 0, i;
int string_len = strlen(string);
char *word;
char s[12] = " .,?!\"'";
char *dup;
dup = strdup(string);
word = strtok(dup, s);
while (word != NULL) {
len = strlen(word);
char *new_word = (char *)malloc(len * sizeof(char));
for (i = 0; i < k; i++) {
new_word = shift_to_right(word);
}
string = replace_word(string, word, new_word);
word = strtok(NULL, s);
}
}
shift_to_right is:
char *shift_to_right(char *string){
char temp;
int len = strlen(string) - 1;
int i;
for (i = len - 1; i >= 0; i--) {
temp = string[i+1];
string[i+1] = string[i];
string[i] = temp;
}
return string;
}
replace_word is:
char *replace_word(char *string, char *word, char *new_word) {
int len = strlen(string) + 1;
char *temp = malloc(len * sizeof(char));
int temp_len = 0;
char *found;
while (found = strstr(string, word)) {
if (strlen(found) != strlen(word) || isDelimitator(*(found - 1)) == 1) {
break;
}
memcpy(temp + temp_len, string, found - string);
temp_len = temp_len + found - string;
string = found + strlen(word)
len = len - strlen(word) + strlen(new_word);
temp = realloc(temp, len * sizeof(char));
memcpy(temp + temp_len, new_word, strlen(new_word));
temp_len = temp_len + strlen(new_word);
}
strcpy(temp + temp_len, string);
return temp;
}
and isDelimitator is:
int isDelimitator(char c) {
if(c == ' ' || c == '.' || c == ',' || c == '?' || c == '!' ||
c == '"' || c == '\0' || c == '\'') {
return 0;
}
else return 1;
}
I tested shift_to_right, replace_word and isDelimitator and work fine. But the final function, operation_3 doesn't work as expected. For example, for input: "Hi I am John" and for k = 1 the output is : "Hi I am John". Basically operation_3 doesn't modify the string. Any advice, corrections please?
There are a few things which I see are possibly the reason for error.
1) In operation_3 you do this : new_word = shift_to_right(word); And, in the definition of char *shift_to_right(char *string) you modify the string itself and return a pointer to it. So, if you called shift_to_right(word) and word = "Hi" then after the execution of shift_to_right both word and new_word are now pointing to the same string "iH", so in replace_word when you pass both the words and check for the substring word you will always get NULL, because, there is no substring "iH".
A possible solution, in shift_to_right add a statement,
char *new_string = strdup(string);
and instead of swapping the characters in string, swap the characters now in new_string and return the new_string from the function.
Your code shall look like this ::
char *shift_to_right(char *string){
char temp;
int len = strlen(string) - 1;
char *new_string = strdup(string);
int i;
for (i = len - 1; i >= 0; i--) {
temp = new_string[i+1];
new_string[i+1] = new_string[i];
new_string[i] = temp;
}
return new_string;
}
2) In the function replace_word, for a moment let us consider that the above mentioned error does not occur and replace_word get called with the parameters :: replace_word(string, "Hi", "iH");.
So, when you perform found = strstr(string, word), it gives you a pointer to the first letter where Hi started. So, in this case, if your string was "Hi I am John", then you get a pointer to the first H, and when you perform strlen(found) you will get 12(length of string left starting from the pointer) as the output, and strlen(word) will always be less (unless found points to the last word in the string), so in most cases your if condition becomes true and you break from the loop, without any swapping.
Moreover, as you yourself pointed out in the comments that strstr will return Johns as well if you want a substring John the only solution for this would be to run a loop and check that in string after John if there is delimiter character or not, if there is no delimiter character, then this is not the substring that you needed.
replace_word shall look something like this ::
void replace_word(char *string, char *word, char *new_word) {
char *found = strstr(string, word);
int len = strlen(word);
while(found) {
char temp = *(found + len);
if(isDelimeter(temp) == 0) {
break;
} else {
found = strstr(found + len + 1);
}
}
if(found != NULL) {
for(int i = 0; i < len; i++) {
*(found + i) = new_word[i]; // *(found + i) is accessing the i^th, character in string from the pointer found
}
}
}
I think this replace_word shall work, you can directly modify the string, and there is no need to actually make a temp string and return it. This reduces the need of allocating new memory and saving that pointer.
I hope this could help!
EDIT :: Since we have been using strdup in the code, which dynamically allocates memory of the size of the string with an extra block for the \0 character, we shall take care of freeing it explicitly, so it will be a good idea according to me free the allocated memory in replace_word just before we exit the function since the new_word is useless after it.
Moreover, I saw a statement in your code::
1) char *new_word = (char *)malloc(len * sizeof(char));
Just before you start the shifting the words, I hope you understand that you do not need to do it. new_word is just a pointer, and since we now allocated memory to it in strdup we do not need to do it. Even before, considering the code that you had written there was no reason to allocate memory to new_word since you were returning the address of the array, which was already in the stack, and would stay in the stack till the end of the execution of the program.
This code is simpler than what you have, and it prints all the word delimiters that were in the input string. And rather than looking for specific punctuation characters, it checks alphanumeric instead.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(void)
{
char instr[] = "Hi! I am 'John' ;)";
int lennin = strlen(instr);
int shifts, i, len, index, start, next;
printf("Working with %s\n", instr);
for(shifts=0; shifts<5; shifts++) { // various examples
printf("Shifts = %d ", shifts);
start = 0;
while(start < lennin) {
while (start < lennin && !isalnum(instr[start])) { // find next alphanum
printf("%c", instr[start]); // output non-alphanum
start++;
}
next = start + 1;
while (isalnum(instr[next])) // find next non-alphanum
next++;
len = next - start;
for(i=0; i<len; i++) { // shift the substring
index = i - shifts;
while(index < 0) index += len; // get index in range
printf("%c", instr[start + (index % len)]); // ditto
}
start = next; // next substring
}
printf("\n");
}
return 0;
}
Program output:
Working with Hi! I am 'John' ;)
Shifts = 0 Hi! I am 'John' ;)
Shifts = 1 iH! I ma 'nJoh' ;)
Shifts = 2 Hi! I am 'hnJo' ;)
Shifts = 3 iH! I ma 'ohnJ' ;)
Shifts = 4 Hi! I am 'John' ;)
I have a dictionary of words stored in a 2D char array. I also have a scanned word stored in a structure. I'm trying to 'thin down' my main dictionary by copying words of length equal to the scanned word into a seperate 2D array. Then I want to print the new array out.
i.e if scanned word = hello, all words of the same length will be copied into the new array.
My code just prints the first word of the array infinitely
words.startword is the scanned word.
void get_equal_length (char equal_length_dictionary[MAX_WORDS][MAX_WORD_LENGTH], char dictionary[MAX_WORDS][MAX_WORD_LENGTH], Scanned_words words)
{
int i, word_count = 0;
for (i = 0; dictionary[i] != '\0'; i++)
{
if (strlen(*dictionary) == strlen(words.startword))
{
strcpy(*equal_length_dictionary, *dictionary);
word_count++;
printf("Word #%d: %s\n", word_count, *equal_length_dictionary);
}
}
printf("Equal length words: %d\n", word_count);
}
for (i = 0; dictionary[i] != '\0'; i++)
{
if (strlen(dictionary) == strlen(words.startword))
{
strcpy(*equal_length_dictionary, *dictionary);
should be:
for (i = 0; dictionary[i][0] != '\0'; i++)
{
if (strlen(dictionary[i]) == strlen(words.startword))
{
strcpy(equal_length_dictionary[i], dictionary[i]);
Also, to improve speed, better calculate strlen(words.startword) only once before the loop, instead of recalculating it inside the loop at each iteration. You should also not forget to terminate the new array with a null string.
The full code will be:
void get_equal_length(char equal_length_dictionary[MAX_WORDS][MAX_WORD_LENGTH], char dictionary[MAX_WORDS][MAX_WORD_LENGTH], Scanned_words words)
{
int i, word_count = 0, len = strlen(words.startword);
for (i = 0; dictionary[i][0] != '\0'; i++)
{
if (strlen(dictionary[i]) == len)
{
strcpy(equal_length_dictionary[i], dictionary[i]);
word_count++;
printf("Word #%d: %s\n", word_count, equal_length_dictionary[i]);
}
}
// now we will also terminate the new array with a null string
equal_length_dictionary[i][0] = '\0';
printf("Equal length words: %d\n", word_count);
}
This should work, although not tested. As Kevin mentioned in the comment, you need to use the index i in the loop. You also should use word_count as index:
void get_equal_length (char equal_length_dictionary[MAX_WORDS][MAX_WORD_LENGTH], char dictionary[MAX_WORDS][MAX_WORD_LENGTH], Scanned_words words)
{
int i, word_count = 0;
for (i = 0; i < MAX_WORDS; i++)
{
char* cur_word = dictionary[i];
if (!cur_word || !*cur_word)
break;
if (strlen(cur_word) == strlen(words.startword))
{
strcpy(equal_length_dictionary[word_count], cur_word);
word_count++;
printf("Word #%d: %s\n", word_count, equal_length_dictionary[word_count]);
}
}
printf("Equal length words: %d\n", word_count);
}