My first function checks for the number of letters that a substring contains from its string.
int num_matches(char* word, char* letters) {
char scrabble[128];
strcpy(scrabble, letters);
int num = 0;
for (int i = 0; i < strlen(word); i++) {
if (strchr(letters, word[i]) == NULL) {
return -1;
}
for (int j = 0; j < strlen(letters); j++) {
if (word[i] == letters[j]) {
num++;
scrabble[j] = '\0';
break;
}
}
}
return num;
}
It returns 4 for "QWOP", "QWOP". However, inside the following function it is returning the same incorrect value for every function call, even when buff and letters print as "QWOP", "QWOP" from my debugging attempt.
void read_words(int num_count[128], char* (*word_idx)[128], int argc, char** argv) {
FILE* fp = fopen(argv[1], "r");
char* letters = argv[2];
int idx = 0;
char buff[128];
int result = 0;
while (fgets(buff, 128, fp) != NULL) {
printf("buff:%s letters:%s\n", buff, letters);
result = num_matches(buff, letters);
printf("result: %d\n", result);
num_count[idx] = result;
char* word = malloc(strlen(buff) + 1);
strcpy(word, buff);
(*word_idx)[idx] = word;
idx++;
result = 0;
}
fclose(fp);
}
buff:QWOP
letters:QWOP
result: -1
My txt file:
ABC
DEFG
QWOP
QWOP
QUOKKA
QUOLL
QUASH
QUANDONG
Since fgets stops at a newline and there are no spaces in my text file, I don't think there should be any problems with reading buff.
fgets reads the data with \n character at the end.
Your function will fail in this case. It is very easy to test:
int main(void)
{
printf("%d\n", num_matches("ABCD", "ABCD"));
printf("%d\n", num_matches("ABCD\n", "ABCD"));
}
Result:
4
-1
You need to remove \n from the buff.
Another problem is the second function. The parameter char* (*word_idx)[128] is a pointer to an array of 128 pointers to char. I do not think that is something you want.
Related
I'm getting this weird error when trying to extract a 2 or 3 digits string of numbers, from a filename in C, some times it executes right, and sometimes it does not, the input filename is "EC2_122016_1676_corte22_03012017084106.TXT", and I only want the part that says "22" out of "corte22".
The correct result in this case should be "Code: 022", but, sometimes it shows another value, like "Code: 223" or "Code: 224", I don't have much experience with C and so, I can't get around to why this is happening, any help?
Here's the code I'm using to separate the filename from the code:
int main(int argc, char *argv[]) {
char *sourceFileName = "EC2_122016_1676_corte22_03012017084106.TXT";
char fileCode[4] = "\0";
strcpy(fileCode, extractFileCode(sourceFileName));
printf("Code: %s\n", fileCode);
}
char* extractFileCode(const char sourceFileName[]) {
char *tmp = strdup(sourceFileName);
strlwr(tmp);
char *result = strstr(tmp, "corte");
result = strtok(result, "_");
result = extractNumbersFromString(result);
char *t;
// convert the number back to string, but add a leading zero
sprintf(result, "%.3d", strtol(result, &t, 10));
free(tmp);
return result;
}
char* extractNumbersFromString(const char *source) {
char *result = malloc(strlen(source) * sizeof(char));
int index = 0;
int i;
for(i = 0; i < strlen(source); i++) {
if(isdigit(source[i])) {
result[index++] = source[i];
}
}
return result;
}
in extractNumbersFromString you're not nul-terminating result (and the buffer is too short), so another digit can slip at the end of the buffer.
Fix:
char* extractNumbersFromString(const char *source) {
char *result = malloc(strlen(source) + 1);
int index = 0;
int i;
for(i = 0; i < strlen(source); i++) {
if(isdigit(source[i])) {
result[index++] = source[i];
}
}
result[index] = '\0';
return result;
}
besides * sizeof(char) is useless since always 1.
I'm trying to create an array of strings and pass strings to this array.
struct node {
int vertex_no;
};
int main() {
char city1[100], city2[100], buffer[999];
int distance;
FILE *fp;
fp = fopen("cities.txt", "r+");
if(fp == NULL)
perror("Error");
//Change - characters with space
while(1) {
char ch = fgetc(fp);
if(ch == '-') {
fseek(fp, ftell(fp)-1, SEEK_SET);
fputc(' ', fp);
}
if(ch == EOF)
break;
}
//Get to beginning of the file
fseek(fp, 0, SEEK_SET);
//Pass first line
fgets(buffer, sizeof(buffer), fp);
int i, j, v = 0;
char cities[100][100];
for(i = 0; i < 100; i++)
for(j = 0; j < 100; j++)
cities[i][j] = '\n';
int vertices = 0;
int add = 1;
//Find how many vertices we have
while(fscanf(fp, "%s %s %d", city1, city2, &distance) == 3) {
if(cities[0][0] == '\n') {
strcpy(cities[0], city1);
strcpy(cities[1], city2);
v = 2;
}
for(i = 0; cities[i][0] != '\n'; i++) {
//Search city1 inside cities array
if( strcmp(cities[i], city1) == 0 ) {
add = 0;
break;
}
//If not found add it to array
if(add) {
strcpy(cities[v], city1);
v++;
}
//Same search for city2
add = 1;
if( strcmp(cities[i], city2) == 0 ) {
add = 0;
break;
}
//If not found add it to array
if(add) {
strcpy(cities[v], city2);
v++;
}
}
}
for(i=0;cities[i][0] != '\n';i++)
printf("City no.%d = %s\n", i, cities[i]);
printf("Last city1, city2 and distance: %s, %s, %d", city1, city2, distance);
return 0;
}
As a result I get
segmentation fault(core dumped)
When I try to do something like this
char *test = NULL;
strcpy(test, "hello");
return 0;
I get the same segmentation fault again. Although when allocate space like this:
char *test = (char *) malloc(100);
There is no problem. But when I do like this:
char test[100];
There is also no problem. So that's why I don't understand the reason of getting segmentation fault even tho I used
char strings[100][100];
instead of
char *strings[100];
Following allocates a single pointer and sets that pointer to point to a single array of 100 characters. I.E. no place to insert 100 city strings.
char *test = NULL;
strcpy(test, "hello");
return 0;
....
char *test = (char *) malloc(100);
....
Following declares an array of 100 bytes with no room for 100 city strings
char test[100];
Following declares an array of 100 character arrays, of which each array is 100 bytes long
char strings[100][100];
Following declares an array of 100 pointers to char, not 100 character strings. So you would need to 'malloc' room for each city string and insert that pointer into the appropriate offset into the array.
char *strings[100];
My program takes in the Constitution, reverses the line order, and prints the Constitution in reverse order back in the command line. When I put the algorithm to reverse the lines in a separate function, lineReversal, the only thing that prints is ▒▒▒.
int main(){
char * buffer;
char * strings[1000];
int arrayCount =0;
int size = 10;
while(!feof(stdin))
{
buffer= (char*) malloc(size);
getAline(&buffer, &size); //gets each line from the Constitution
strings[arrayCount++] = buffer;
}
lineReversal(&strings);
return 0;
}
char lineReversal(char ** stringPtr)
{
char * strings = *stringPtr;
for(int i = 873; i >=0 ; i--) {
if(strings[i] == '\0'){
break;
}
printf("%s", strings + i);
}
*stringPtr = strings;
return 0;
}
If I put that algorithm into main() and run my program, this is my output:
H▒▒▒▒▒▒▒▒▒▒▒▒Dhave intervened.Representatives, shall take effect, until an election of Representatives shall
The expected output is:
have intervened.
This is what my program looks like with the algorithm inside main.
int main(int argc, char ** argv){
char * buffer;
char * strings[1000];
int arrayCount =0;
int size = 10;
while(!feof(stdin))
{
buffer= (char*) malloc(size);
getAline(&buffer, &size);
strings[arrayCount++] = buffer;
}
for(int i = 873; i >=0 ; i--)
{
if(strings[i] == '\0'){
break;
}
printf("%s", strings[i]);
}
return 0;
}
I have a program that uses word search. I have a data file which contains the puzzle and the words. What can i implement into my program so that it reads the file and stores the letters present in it as an array?
Example of the data file (it is called testdata):
h e l l o a c d
f g b w o r l d
h a c c v b n a
e q b x n t q q
y e h n c a q r
hello
world
hey
I want to store all the letters in a 2-d array.
Also, I need to store all the words in a 1-dimensional array.
The maximum number of rows of columns or rows that AxA square of letters that is possible in a data file is 25. So, I believe that I should declare an array of that size for the letter and then write them into that array.
I just can't figure out how to read them into that array. There is a space after each letter in the array and no spaces in the words so I think that might be helpful when putting the letters in one array and words in another.
Given your question, and your input, there are a few questions, but in the interest of time, for now, I have made some assumptions about the dimensions of the array, i.e. that it is not necessarily square (as implied by columns or rows that AxA square). The actual data sample disagrees, so I wrote a routine that counts everything as it goes. The letter array is simply an array of arrays, but since it is stored in sequential memory, it just looks like one long array. The strings are each in there own location as well. In any case, this code should illustrate enough to get you on the right track...
#include <ansi_c.h>
#include <stdio.h>
void GetFileContents(char *file, int *nWords, int *lw, int *r, int *c);
void allocMemoryStr(int numStrings, int max);
void allocMemoryLtr(int numStrings, int max);
void freeMemoryStr(int numStrings);
void freeMemoryLtr(int numletters);
#define FILENAME "c:\\dev\\play\\_puzzle.txt"
char **letters;
char **strings;
int main()
{
int longest, cnt, wCount, rows, cols, i;
char line[260];
FILE *fp;
char *buf=0;
GetFileContents(FILENAME, &wCount, &longest, &rows, &cols);
allocMemoryStr(wCount, longest); //for strings
allocMemoryLtr(rows*cols, 1); //for strings
//read file into string arrays
fp = fopen(FILENAME, "r");
cnt=0;
for(i=0;i<rows;i++)
{
fgets(line, 260, fp);
buf = strtok(line, " \n");
while(buf)
{
strcpy(letters[cnt], buf);
buf = strtok(NULL, " \n");
cnt++; //use as accurate count of words.
}
}
cnt=0;
while(fgets(line, 260, fp)) //get remainder of lines into strings
{
//[EDIT]removed fgets()
buf = strtok(line, " \n");
while(buf)
{
strcpy(strings[cnt], buf);
buf = strtok(NULL, " \n");
cnt++; //use as accurate count of words.
}
}
fclose(fp);
freeMemoryStr(wCount);
freeMemoryLtr(rows*cols);
return 0;
}
void GetFileContents(char *file, int *nWords, int *lw, int *r, int *c)
{
char line[260];
FILE *fp;
char *buf=0;
char temp[80];
int wc=0, rc=0, cc=0, ck=0;
fp = fopen(FILENAME, "r");
while(fgets(line, 260, fp))
{
rc++;
buf = strtok(line, " \n");
while(buf)
{
strcpy(temp, buf); // word handler
if(strlen(temp) > 1)
{
wc++;
rc--; //
}
else if(strlen(temp) == 1) //leter handler
{
cc++;
(cc>ck)?(ck=cc):(cc=cc);
}
buf = strtok(NULL, " \n");
}
cc = 0;
}
fclose(fp);
*nWords = wc;
*r = rc;
*c = ck;
}
void allocMemoryStr(int numStrings, int max)
{
int i;
strings = calloc(sizeof(char*)*(numStrings+1), sizeof(char*));
for(i=0;i<numStrings; i++)
{
strings[i] = calloc(sizeof(char)*max + 1, sizeof(char));
}
}
void allocMemoryLtr(int numletters, int max)
{
int i;
letters = calloc(sizeof(char*)*(numletters+1), sizeof(char*));
for(i=0;i<numletters; i++)
{
letters[i] = calloc(sizeof(char)*max + 1, sizeof(char));
}
}
void freeMemoryStr(int numStrings)
{
int i;
for(i=0;i<numStrings; i++)
if(strings[i]) free(strings[i]);
free(strings);
}
void freeMemoryLtr(int numletters)
{
int i;
for(i=0;i<numletters; i++)
if(letters[i]) free(letters[i]);
free(letters);
}
I would parse the file line by line and char by char looking for what i need. In the example (which is untested), i hold three counters to help filling the arrays correctly.
char letters[25][25];
char words[10][25]
int letters_x_pos = 0; // Row counter
int letters_y_pos = 0; // Column counter
int words_pos = 0;
for (int i = 0; i < 25; i++) {
for (int j = 0; j < 25; j++) {
letters[i][j] = '\0';
}
}
const char *line;
while (line = some_read_function()) {
if (!(strlen(line) > 1)) {
continue;
}
if (line[1] == ' ') {
// Line contains letters
const char *letter = line;
while (*letter != '\0') {
if (*letter == ' ' || *letter == '\n' || *letter == '\r') {
continue;
}
else {
letters[letters_x_pos][letters_y_pos++] = *letter;
}
if (letters_y_pos == 25) {
// Maximum reached
break;
}
letter++;
}
// Increment row counter and reset column counter
letters_x_pos++;
letters_y_pos = 0;
if (letters_x_pos == 25) {
// Maximum reached
break;
}
}
else {
// Line contains word
strncpy(words[words_pos++], line, 25);
if (words_pos == 25) {
// Maximum reached
break;
}
}
}
wordCur is a string of capital letters, and dictionary is an array of strings, no matter what I input into wordCur, I am always returned 0.
Edit: I updated the code a little bit, and added an abridged version of the rest of the program for some context. As it is shown here, it just crashes when it gets to checkValid
int main() {
FILE *ifp;
ifp = fopen("dictionary.txt", "r");
int* lDist[26];
int* lUsed[26];
int dictLen;
int i;
fscanf(ifp, "%d", &dictLen);
char dictionary[dictLen][7];
char* letters[7];
int scoreCur = 0;
int scoreHi = 0;
char wordCur[7];
char wordHi[7];
int isWord = 0;
//reads the dictionary into the array
for (i = 0; i < dictLen; i++) {
fscanf(ifp, "%s", &dictionary[i]);
}
scanf("%s", wordCur);
isWord = checkValid(wordCur, dictLen, dictionary);
if (isWord == 1) {
scoreCur = calcScore(wordCur);
}
//fclose(ifp); not sure why, but this causes a crash
return 0;
}
int checkValid (char *wordCur,int dictLen, char dictionary[dictLen]) {
int valid = 0;
int i;
for (i = 0; i < dictLen; i++){
int helper = strcmp(wordCur, dictionary[i]);
if (helper = 0){
valid = 1;
}
}
wordCur is a string of capital letters
int checkValid (char wordCur,int dictLen, char dictionary[dictLen])
No, wordCur is a single character. Not a string. A string in C is represented as an array of characters, terminated by a character with the value 0. You need a pointer argument, char *wordCur.
Your code should probably look more like this:
int checkValid(const char *wordCur, // word to search for (string)
int dictLen, // no of entries in dictionary
char dictionary[][7]) // dictionary (array of strings)
{
int valid = 0;
int i;
for (i = 0; i < dictLen; i++)
{
if (strcmp(wordCur, dictionary[i]) == 0)
{
valid = 1;
break;
}
}
return valid;
}
wordCur is a string of capital letters, and dictionary is an array of strings
Try this:
int checkValid (const char *wordCur,int dictLen, const char *dictionary[])
By the way, you keep searching, even after you found what you are looking for, and the comaprison is wrong anyway for strings. I suggest:
for (i = 0; i < dictLen; i++){
if (strcmp(wordCur, dictionary[i]) == 0){
valid = 1;
break;
}
}