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.
Related
In this code, the string is split by the difference of the space. I could do that through strtok but I didn't. I just want to know that how can split the strings by assigning tokens to them, like if I want to print the first token then it should print the first word from the string. Similarly, if I want to print the second word then it should print the second word after the first space occurred and so on.
int main(){
char inputString[100], words[10][10];
int indexCtr = 0, wordIndex = 0, totalWords = 0;
printf("Input a string: ");
fgets(inputString, sizeof(inputString), stdin);
for(indexCtr = 0; indexCtr <= strlen(inputString); indexCtr++){
if(inputString[indexCtr] == ' ' || inputString[indexCtr] == '\0'){
words[totalWords][wordIndex] = '\0';
totalWords++;
wordIndex = 0;
}
else{
words[totalWords][wordIndex] = inputString[indexCtr];
wordIndex++;
}
}
printf("\nWords from the string are:\n");
for(indexCtr = 0; indexCtr < totalWords; indexCtr++){
printf("%s\n", words[indexCtr]);
}
return 0;
}
as an idea with strncpy(...):
char input[100] = " 1 2 3 4 5 "
"one two three four five";
char words[10][10] = { 0 };
size_t w_counter = 0;
for (size_t i = 0; i < strlen (input); i++) {
while (input[i] != '\0' && isspace (input[i])) {
i++;
}
char* start = &input[i];
while (input[i] != '\0' && !isspace (input[i])) {
i++;
}
strncpy (words[w_counter++],
start,
&input[i] - start);
}
//output
for (size_t i = 0; i < w_counter; i++){
puts (words[i]);
}
I'm getting some unwanted output when attempting to parse a comma seperated value file with strsep(). It seems be be working for half of the file, with a number with only one value (ie. 0-9), but as soon as multiple values are added like for instance 512,
It will print 512 12 2 512 12 2 and so on. I'm not exactly sure if this is due to the particular style that I'm looping? Not really sure.
int main() {
char line[1024];
FILE *fp;
int data[10][10];
int i = 0;
int j = 0;
fp = fopen("file.csv", "r");
while(fgets(line, 1024, fp)) {
char* tmp = strdup(line);
char* token;
char* idx;
while((token = strsep(&tmp, ","))) {
for (idx=token; *idx; idx++) {
data[i][j] = atoi(idx);
j++;
}
}
i++;
j=0;
free(tmp);
}
for(i = 0; i < 10; i++) {
for(j = 0; j < 10; j++) {
printf("%d ", data[i][j]);
}
printf("\n");
}
fclose(fp);
}
It is because you are creating elements by using every characters in the token returned by strsep() as start via the loop
for (idx=token; *idx; idx++) {
data[i][j] = atoi(idx);
j++;
}
Stop doing that and create just one element from one token to correct:
while((token = strsep(&tmp, ","))) {
data[i][j] = atoi(token);
j++;
}
Also free(tmp); will do nothing because tmp will be set to NULL by strsep(). To free the buffer allocated via strdup(), keep the pointer in another variable and use it for freeing.
So basically what my program did before i had to change it so that it would accept arbitrary values, was to take x-amount of words and the size of the words would also be arbitrary. (both are user inputted). I did this via a multiArray.
Then sorted according to alphabetical-order.
I'm just going to put it out there as my code is shit and I'm very unfamiliar with the usage of arbitrary-strings and pointers. I've read up on it in the manual but the concept needs to sink in a little bit first i believe. Anyhow, I get the error: "Abort trap: 6" when i run the program. Could anyone please help me fix this problem so that i can see how the code would look like if it was actually working, i think that would help me understand both pointers and allocating memory a lot better. Forever in debt if you do.
Current code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_LENGTH 10
int main(){ //8
char *name;
char tname[] = {0};
char temp[] = {0};
int i=0, j=0, n=0;
ssize_t bytes_read;
size_t bytes_number;
printf("Enter the amount of words you want to input: ");
scanf("%d", &n);
printf("Enter %d words: ",n);
bytes_number = MAX_LENGTH;
name = (char *) malloc (bytes_number+ 1);
bytes_number = 0;
bytes_read = getline(&name, &bytes_number, stdin);
if (bytes_read == -1){
puts("ERROR!");
free(name);
}
for (i = 0; i < n; i++){
strcpy(&tname[i], &name[i]);
}
for (i = 0; i < n - 1 ; i++){
for ( j = i + 1; j < n; j++){
if (strcmp(&name[i], &name[j]) > 0){
strcpy(temp, &name[i]);
strcpy(&name[i], &name[j]);
strcpy(&name[j], temp);
}
}
}
printf("\n------------------------------------------\n");
printf("%-3s %4s %11s\n", "Input","|", "Output");
printf("------------------------------------------\n");
for (i = 0; i < n; i++)
{
printf("%s\t\t%s\n", &tname[i], &name[i]);
}
printf("------------------------------------------\n");
}
This
strcpy(&tname[i], &name[i]);
is completely wrong, if you just want to copy all the characters, then it's just
strcpy(tname, name);
which is equivalent to
for (size_t i = 0 ; name[i] != '\0' ; ++i)
tname[i] = name[i];
using strcpy(&tname[i], &name[i]) is wrong because it will copy all the bytes from name until '\0' is found, at every loop starting at the i-th character.
But this will fail again because tname is does not have room, it's an array with just one element.
Since you want to sort the strings, you DO NOT NEED TO COPY them. Just swap the pointers. Also
char temp[] = {0};
only allocates 1 character, thus
strcpy(temp, name);
will invoke Undefined Behavior.
Try this, maybe it's what you need
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int
main(void)
{
char **words;
char *temp;
int word_count;
int actual_count;
char *word;
size_t length;
int result;
printf("Enter the amount of words you want to input: ");
if (scanf("%d%*c", &word_count) != 1)
return -1; // Input error
printf("Enter '%d' words:\n", word_count);
words = NULL;
word = NULL;
result = -1;
actual_count = 0;
length = 0;
for (int i = 0 ; i < word_count ; ++i)
{
char **pointer;
printf("Word(%d) > ", i + 1);
if ((length = getline(&word, &length, stdin)) <= 0)
goto cleanup;
// Grow the array of words
pointer = realloc(words, (i + 1) * sizeof(*pointer));
if (pointer == NULL)
goto cleanup; // Memory Exhausted
// Now it's safe to overwrite `words'
words = pointer;
words[i] = malloc(length);
if (words[i] == NULL)
goto cleanup; // Memory Exhausted
memcpy(words[i], word, length);
words[i][length - 1] = '\0'; // Replace '\n' with '\0'
actual_count += 1;
}
printf("Input : ");
for (int i = 0 ; i < actual_count ; ++i)
printf("%s\t", words[i]);
printf("\n");
for (int i = 0; i < actual_count - 1 ; i++)
{
for (int j = i + 1 ; j < actual_count ; ++j)
{
if (strcmp(words[i], words[j]) <= 0)
continue;
temp = words[i];
words[i] = words[j];
words[j] = temp;
}
}
printf("Output: ");
for (int i = 0 ; i < actual_count ; ++i)
printf("%s\t", words[i]);
printf("\n");
result = 0;
cleanup:
free(word);
for (int i = 0; i < actual_count ; i++)
free(words[i]);
free(words);
return result;
}
Note: This would consider an empty word (made completely of white space characters), as a valid word.
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);
}
I have some code that is trying to take in data from a file. the format is like this : 9/2d 0/1s. There could be multiple of those in the file but i need to take the first number and set it as the index to add at. Then I need to save the next number and character as separate values. I have some code here but it doesn't work so well.
struct matrix tokens[nbrState][12];
int *num = 0;
int index = 0;
while ((ptr = fgets(buf, 256, fp)) != NULL){
ptrToken = strtok(buf, "/");
int count = 0;
for(int r = 0; r < 12; r++){
if(count >= 3){
ptrToken = strtok(NULL, " ");
index = atoi(ptrToken);
tokens[index][r].state = index;
}
count++;
}
}
Here is my updated code. It works abit better.
struct matrix tokens[nbrState][12];
char *tok;
int index = 0;
int state = 0;
while((ptr = fgets(buf, 256, fp)) != NULL){
ptrToken = strtok(buf, " ");
tok = ptrToken;
//index = strtok(tok, "/");
for(int r = 0; r < 12; r++){
index = atoi(tok);
state = atoi(ptrToken);
tokens[index][12].state = state;
}
}
You could try this
while ( ( fscanf ( fp, "%d/%d%c", &index, &separateInt, &separateChar) == 3) {
// use values as needed
tokens[index][11].state = sepatateInt;
}
The loop will continue until EOF or input from the file does not match the format.