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;
}
Related
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.
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.
My homework requires me to write a program that takes a string from the terminal (argc and argv) and print every possible permutation. I have tried to use Heap's Algorithm, but it doesn't seem to be working out. Below is my function.
char **getPermutation(char * in)
{
//n is the size of the input string.
int n = strlen(in);
int count[n];
int counter= 0;
char copy[n];
char **permutations = malloc(sizeof(char*)*(factorial(n)));
permutations[0] = in;
strcpy(in, copy);
counter++;
for( int i = 1; i < n;)
{
if (count[i] < i){
if (i%2==0){
swap(&in[0],&in[i]);
}
else
{
swap(&in[count[i]],&in[i]);
}
permutations[counter] = in;
strcpy(in, copy);
counter++;
count[i]++;
i = 1;
}
else
{
count[i] = 0;
i++;
}
}
return permutations;
}
The function must return the pointer to the character pointer as specified by the instructions. That's also why there are so many variables (although, I'm not really sure what to do with the copy of the string. I'm fairly sure I need it). Testing shows that the program will loop, often too much and eventually hit a seg fault. It doesn't seem like the swapped strings make it into the returned array on top of that.
Below is a rework of your code with cleaned up memory allocation and it addresses some problems mentioned in the above comments. Additionally, you have a bug in your algorithm, this statement strcpy(in, copy); keeps you from getting all the permutations (causes repeats instead.) This code works but isn't finished, it can use more error checking and other finishing touches:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
unsigned int factorial(unsigned int n)
{
/* ... */
}
void swap(char *a, char *b)
{
/* ... */
}
char **getPermutations(const char *input)
{
char *string = strdup(input);
size_t length = strlen(string);
char **permutations = calloc(factorial(length), sizeof(char *));
int *counts = calloc(length, sizeof(int)); // point to array of ints all initialized to 0
int counter = 0;
permutations[counter++] = strdup(string);
for (size_t i = 1; i < length;)
{
if (counts[i] < i)
{
if (i % 2 == 0)
{
swap(&string[0], &string[i]);
}
else
{
swap(&string[counts[i]], &string[i]);
}
permutations[counter++] = strdup(string);
counts[i]++;
i = 1;
}
else
{
counts[i++] = 0;
}
}
free(counts);
free(string);
return permutations;
}
int main(int argc, char *argv[])
{
char *string = argv[1];
char **permutations = getPermutations(string);
unsigned int total = factorial(strlen(string));
for (unsigned int i = 0; i < total; i++)
{
printf("%s\n", permutations[i]);
}
free(permutations);
return 0;
}
OUTPUT
> ./a.out abc
abc
bac
cab
acb
bca
cba
>
The function makearg is supposed to count the number of words in a char array and also break each word up into their own spot in a pointer array.
Segmentation fault seems to be a problem with the strncpy function.
int makearg(char s[], char ***args);
int main(){
char **args = (char**)(malloc(100));
char *str = "ls is a -l file";
int argc;
argc = makearg(str, &args);
printf("%d", argc);
printf("%c", '\0');
int i;
for(i = 0; i < argc; i++){
puts(args);
printf("%c", '\n');
}
return 0;
}
/////////////////////////////////////////
int makearg(char s[], char ***args){
int argc = 0;
int charc = 0;
int wordstart = 0;
while(1){
if(s[charc] == '\0'){
strncpy(*args[argc], s + wordstart, charc - wordstart);
args[argc][(charc - wordstart) + 1] = '\0';
argc++;
break;
}
if(s[charc] == ' '){
strncpy(*args[argc], s + wordstart, charc - wordstart);
args[argc][(charc - wordstart) + 1] = '\0';
wordstart = charc + 1;
argc++;
charc++;
}
else{
charc++;
}
}
return argc;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int makearg(const char s[], char ***args);
int main(void){
char **args = NULL;
const char *str = "ls is a -l file";
int argc = makearg(str, &args);
printf("argc : %d\n", argc);
int i;
for(i = 0; i < argc; i++){
puts(args[i]);
free(args[i]);
}
free(args);
return 0;
}
int wordCount(const char *s){
char prev = ' ';
int wc = 0;
while(*s){
if(isspace(prev) && !isspace(*s)){
++wc;
}
prev = *s++;
}
return wc;
}
int makearg(const char s[], char ***args /*out*/){
int argc = wordCount(s);
int len;
if(argc == 0){
*args = NULL;
return 0;
}
*args = malloc(argc * sizeof(char*));
argc = 0;
while(1){
while(isspace(*s))
++s;
if(EOF==sscanf(s, "%*s%n", &len))
break;
(*args)[argc] = malloc(len + 1);
strncpy((*args)[argc], s, len);
(*args)[argc++][len] = '\0';
s += len;
}
return argc;
}
You allocated space for the args array of pointers, but you never allocate space for the strings you intend to store in them, so when you try to store the strings in makearg, you are interpreting whatever random garbage is there as a pointer, and that's not going to work.
Also, you only allocate 100 bytes for the pointer array -- it's not clear how many
words you expect to be able to split, but the malloc call should probably look more like
char **args = malloc(MAX_WORDS * sizeof(char *)); /* no cast required */
then follow that with a loop to do MAX_WORDS more malloc calls, in order to initialize args with valid pointers.
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;
}
}
}