i have an assignment where i have to extract the respective morse code per word that is stored in a text file. it's a word and it's code per line so i save the whole line and try to separate the string as: Y = ..-.
char letter;
char meaning[30][30];
char letters[30];
while(i<30){
int i =0;
gets(code,10,fPointer);
//i save the position 0 in the char array because the letter is always is the 1st position
letter = code[0];
letters[i]= letter;
i++;
int S = strlen(code);
for(int f=3;f<=N;f++){
//i need to save the rest of the line in a different array but i don't know how}
i'm new to programming so i don't really know too many functions so ideas on how to solve them or new functions will be welcome
basically i know how to take the whole line and put it in an array, the first position i save it as it is the letter and the rest i don't know how to separate it
i want 2 arrays
array1[30] = "a" ,"b", "c",
array2[30][30] = ".--", "..-",
so a and it's code are both in the position 0 and all the other letters
You can simply use strcpy() to copy the rest of the line to meanings[i].
You shouldn't initialize i = 0; inside the loop, since then it will never reach 30. And you shouldn't increment i until after you copy to meanings[i]. You can use a for loop instead of while to simplify all of this.
for (i = 0; i < 30; i++){
char *res = fgets(code,10,fPointer);
if (!res) { // EOF or error
break;
}
//i save the position 0 in the char array because the letter is always is the 1st position
letter = code[0];
letters[i]= letter;
int S = strlen(code);
if (code[S-1] == '\n') { // trim newline
code[S-1] = '\0';
}
strcpy(meaning[i], &code[4]);
}
You can also use sscanf() to extract parts of the line.
for (i = 0; i < 30; i++){
char *res = fgets(code,10,fPointer);
if (!res) { // EOF or error
break;
}
if (sscanf(code, "%c = %s", &letters[i], meaning[i]) != 2) {
break; // line isn't formatted correctly
}
}
Related
im trying to add words from a file into a 2d array , the problem is that after the 7th word , the words start to shape up wierdly , does anyone knows that might cause this?
void count_words(WordCount **wclist, FILE *infile)
{
int num_words = 0;
char ch;
int k=0;
char **pook;
int flagA=0;
pook = malloc(4096*sizeof(char*));//creates a 2d array for every word from the file
for(int i = 0 ; i <4096 ; i++)
{
pook[i] = malloc(50 * sizeof(char*));
}
while((ch=fgetc(infile))!=EOF)
{
ch=tolower(ch);
if(flagA==0)
{
if(isalpha(ch)!=0)
{
num_words++;
flagA=1;
strcat(pook[k]+0, &ch);
}
}
else
{
if(isalpha(ch)!=0)
{
strcat(pook[k]+0, &ch);
}
else
{
flagA = 0;
k++;
}
}
}
for(int i =0 ; i < num_words ;i++)
{
printf("%s\n",pook[i]);
add_word(wclist , pook[i]);
}
}
the input :
input is text file that contains :
ilona.txt
main.c
makefile
wc_sort.o
word_count.c
word_count.h
words
this is how the output should look like :
ilona
txt
main
c
makefile
wc
sort
o
word
count
c
word
count
h
words
this is how the output realy is :
the output is :
ilona
txt
main
c
makefile
wc
sort
o
w o r d
c
o
u
n
t
c
w
o
r
d
t
h
words
*/
So your code has several mistakes, and I'm sure that as you will gain experience, your code will be less messy.
Previous comments have pointed to some of the bugs, so I'll just list them by order:
When you use 'malloc', it doesn't reset the values in the memory cells, so either you do it yourself, or as I suggest, just use 'calloc' - it's a better habit IMO.
You should check that the pointer you allocated memory to, hasn't received a NULL value (because the allocation has failed).
You first allocate memory for the pointers to the character arrays (AKA the number of strings), then allocate memory for the number of characters for each string). Notice that you have a mistake: pook[i] = malloc(50 * sizeof(char*));. This should be pook[i] = malloc(50 * sizeof(char)); because the second allocation is for characters and not pointers to characters.
Though the statement strcat(pook[k]+0, &ch); should be okay since &ch is a pointer to a character like declaring an array and using the pointer to the array, though note yourself that most compilers probably won't let you do that; In fact, I tried compiling your code in VS 2019, and it didn't even let me build it because strcat is an un-safe function.
In pook[k]+0, the zero is irrelevant, and can cause problems to the compilation as it sometimes might identify it as an arithmetic argument, instead of a pointer.
Also, IMO you should add comments before uploading your code, so It would be easier for other people to understand your code and help you find the solution faster, saving you time. Also, it's a must-do habit because you almost always will show other people your code, and even help you if you get lost in your own code.
My version of what you tried to do is the following:
void count_words (FILE* infile)
{
char** pook;
pook = calloc(4096,sizeof(char*)); // Allocate the number of strings
for (int i = 0; i < 4096; i++)
{
pook[i] = calloc(50, sizeof(char)); // Allocate the number of characters for each string
}
int num_words = 0, letter = 0; // Initialize a counter for the amount of words and letters
int flag = 0; // Initialize a flag that represents if we are currently in a word or not.
char ch; // A temp character
while ((ch = fgetc(infile)) != EOF)
{
if (isalpha(ch) == 0 && flag == 0) // If the current character isn't a letter, and we didn't start to read a word:
continue;
else if (isalpha(ch) == 0 && flag == 1) // If the current character isn't a letter, and we finished to read a word:
{
++num_words; // Because we finished reading a new word
flag = 0; // Because we're not in a word anymore
letter = 0; // Same as above
}
else if (isalpha(ch) != 0 && flag == 0) // If this is the first letter in the current word:
{
pook[num_words][letter] = ch; // Insert the value of the current character
++letter; // Advance to the next letter of pook[num_words]
flag = 1; // Because we're currently in a word
}
else if (isalpha(ch) != 0 && flag == 1) // If this is not the first letter of the current word:
{
pook[num_words][letter] = ch; // Insert the value of the current character
++letter; // Advance to the next letter of pook[num_words]
}
}
if (flag == 1) // If the last character before the EOF is still part of the word, we need to increment the num of words.
++num_words;
for (int i = 0; i < num_words; i++)
{
printf("%s\n", pook[i]);
}
}
The output is the following:
ilona
txt
main
c
makefile
wc
sort
o
word
count
c
word
count
h
words
Hope I helped,
Good luck!
I'm studying elementary programming in C and I'm doing a challenge to determine the reading age of various sentences. This is achieved by determining the amount of sentences in a string etc. I have some code that does the my first very basic step but it's not quite working as expected.
I'm thinking this is because my knowledge of the strlen function etc isn't sufficient.
I don't want to cheat for the answer as I like the sense of achievement from the problem solving. But would it be possible to get a gentle push in the right direction if at all possible?
char sentence[] = "One fish. Two fish. Red fish. Blue fish.";
int main(void)
{
int sentence_count = 0;
int word_count = 0;
int i;
int length = strlen(sentence);
for (i = 0; i == strlen(sentence); i++) //need to somehow go through a string one char at a time until the end.
{
if (sentence[i] == '.' || sentence[i] == '!' || sentence[i] == ';' || sentence[i] == '?')
{
return sentence_count ++;
}
if (sentence[i] == '\0')
{
return word_count ++;
}
}
printf("There are %i in %i sentences.\n", word_count, sentence_count);
printf("%i\n", length);
}
First Problem -
for (i = 0; i == strlen(sentence); i++)
This state should be -
for (i = 0; i < strlen(sentence); i++)
In your case, it would be terminating on the first iteration itself. However, You need to loop until you have reached the index - strlen(sentence).
Do recall that for loop has syntax - for(initialisation; condition; increment/decrement) will run only until the condition evaluates to true. So, you need the condition to evaluate to true till you have traversed the whole string which is done by the second line of code mentioned above.
A better alternative approach would be -
for (i = 0; sentence[i] != '\0'; i++)
which means the loop will run until you encounter a null-terminated character.
Second Problem -
return sentence_count ++;
.
.
return word_count ++;
Here, you don't need to add the return keyword before the above two statements. The return will directly exit from your program. Simply writing sentence_count++ and word_count++ would be correct.
Third Problem -
sentence[i] == '\0'
This statement doesn't quite fit with the logic that we are trying to achieve. The statement instead must check if the character is a space and then increment the word count -
if (sentence[i] == ' ')
{
return word_count ++;
}
Your for loop condition is the main problem; for (i = 0; i == strlen(sentence); i++) reads as "on entry, set i to 0, enter the body each time i is equal to the length of sentence, increment i at the end of each loop". But this means the loop never runs unless sentence is the empty string (has strlen of 0). You want to test i < strlen(sentence) (or to avoid potentially recomputing the length over and over, use the length you already calculated, i < length).
You also need to remove your returns; the function is supposed to count, and as written, it will return 0 the instant it finds any of the target characters, without using the incremented values in any way. Put a return 0; at the end of main to indicate exiting successfully (optionally, stdlib.h can be included so you can return EXIT_SUCCESS; to avoid magic numbers, but it's the same behavior).
The information in others answers being already covered, here are a couple of other suggestions for your consideration.
Remove function calls, such as strlen() from within the for(;;) loop. You've already obtained the length with:
int length = strlen(sentence);
Now, just use it in your for loop:
for(i = 0; i < length ; i++)//includes replacement of == with <
Encapsulate the working part of your code, in this case the the counting of words and sentences. The following uses a different approach, but its the same idea:
//includes deliminators for common end-of-sentence punctuation:
int count_sentences(const char *buf)
{
const char *delim = {".?!"};//add additional 'end-of-sentence' punctuation as needed.
char *tok = NULL;
int count = 0;
char *dup = strdup(buf);//preserve original input buffer
if(dup)
{
tok = strtok(dup, delim);
while(tok)
{
count++;
tok = strtok(NULL, delim);
}
free(dup);
}
return count;
}
One additional idea, that is out of scope with your original code, but very useful in practice is to remove any parts of the buffer that may not be part of the sentence, i.e. leading or trailing space. In your example, you have the test case for your sentences tightly defined within a string literal:
char sentence[] = "One fish. Two fish. Red fish. Blue fish.";
This is not incorrect, but what would happen at some point your code were to be expected to work with string buffers not so neatly packaged? i.e. leading or trailing white space characters in the buffer to be processed?
"\n\n\tOne fish. Two fish. Red fish. Blue fish.\f"
Removing unknown and unwanted content from the buffer prior to processioning simplifies the code doing the work, in this case counting sentences. Following is a simple example of how this can be done.
//prototype:
char *new = clear_leading_trailing_whitespace(sentence);
char * clear_end_space(const char *buf)
{
char *new = buf;
//clear leading whitespace
while (isspace(*new))
{
new++;
}
//clar trailing whitespace
int len = strlen(new);
while(isspace(*(new + len-1)))
{
len--;
}
*(new + len) = 0;
return buf;
}
Next, the following code segment is intending to count words:
if (sentence[i] == '\0')
{
return word_count ++;
}
But after being initialized to 0, word_count is only incremented once when seeing the null terminator, \0 once. Word count is generally a count of spaces between non-sentence terminating and non-whitespaces characters in a buffer. Or in otherwords, tracking how many clusters of non-whitespace there are. The following is a way to do this:
void countwords(const char *text, *count)
{
bool reading_word = false; // Flag
int words = 0;
for(int i=0; i<strlen(text); i++)
{
if(isspace(text[i])) {
reading_word = false;
}
else if(isalpha(text[i])) {
if(!reading_word) {
reading_word = true;
words++;
}
}
}
*count = words;
}
Functions like this can be used to greatly simplify contents of the main function:
char sentence[] = "One fish. Two fish. Red fish. Blue fish.";
int main(void)
{
int sentence_count = 0;
int word_count = 0;
char *new = clear_leading_trailing_whitespace(sentence);
countwords(new, &word_count);
sentence_count = count_sentences(new);
...
printf("There are %d words in %d sentences.\n", word_count, sentence_count);
}
Currently I am coding a program that can go through a text file and analyze each character. If a character is alphanumeric and a valid identifier, I want to be able to add that character into a string.
My current code to do so is this:
char final[256]={'\0'};
unsigned int len = 0;
static int current = ' ';
static int temp = ' ';
if(isalpha(current)){
final[0]=current;
len = 1;
for (temp = fgetc(file); isalnum(temp) || temp == '_';){
for(int i = len; i <= len; i++){
final[i] = temp;
len++;
}
}
final[len] = '\0';
Am I correct to approach this problem the current way? Can you add characters to index positions of strings in C?
The code itself is simple.
char final[256];
unsigned int len = 0;
final[len] = fgetc(file); //we read the character but do not "approve" it.
//while (!isalpha(final[len])) final[len] = fgetc(file); //uncomment if you want to read the file until a valid identifier begins. Also it's barely an example: it lacks EOF check.
if(isalpha(final[len])){
len = 1; //We "approve" the first character
while ( isalnum( final[len] = fgetc(file) ) || final[len] == '_') //In C, conditions are checked left to right so if isalnum()==0 we check for '_' with correctly updated final[len] value.
len++; //We "approve" the next character;
}
}
final[len] = 0; //The last character has been read but not "approved" so we overwrite it with null-term.
About the second question... yes, you can add a character to an indexed position. But it must be either last position or it'll overwrite an existing one. If you want to insert some characters, use memmove() function first.
I'm having trouble with trying to manipulate 2d dynamic arrays in C. What I want to do is to store a char string in every row of the the 2d array then perform a check to see if the string contains a certain character, if so remove all occurrences then shift over the empty positions. What's actually happening is I get an exit status 1.
More about the problem, for example if I have
Enter string 1: testing
Enter string 2: apple
Enter string 3: banana
I would want the output to become
What letter? a // ask what character to search for and remove all occurences
testing
pple
bnn
Here is my full code:
#include <stdio.h>
#include <stdlib.h>
void removeOccurences2(char** letters, int strs, int size, char letter){
// Get size of array
// Shift amount says how many of the letter that we have removed so far.
int shiftAmt = 0;
// Shift array says how much we should shift each element at the end
int shiftArray[strs][size];
// The first loop to remove letters and put things the shift amount in the array
int i,j;
for(i=0;i < strs; i++){
for(j = 0; j < size - 1; j++) {
if (letters[i][j] == '\0'){
break;
}
else {
// If the letter matches
if(letter == letters[i][j]){
// Set to null terminator
letters[i][j] = '\0';
// Increase Shift amount
shiftAmt++;
// Set shift amount for this position to be 0
shiftArray[i][j] = 0;
}else{
// Set the shift amount for this letter to be equal to the current shift amount
shiftArray[i][j] = shiftAmt;
}
}
}
}
// Loop back through and shift each index the required amount
for(i = 0; i < strs; i++){
for(j = 0; j < size - 1; j++) {
// If the shift amount for this index is 0 don't do anything
if(shiftArray[i][j] == 0) continue;
// Otherwise swap
letters[i][j - shiftArray[i][j]] = letters[i][j];
letters[i][j] = '\0';
}
//now print the new string
printf("%s", letters[i]);
}
return;
}
int main() {
int strs;
char** array2;
int size;
int cnt;
int c;
char letter;
printf("How many strings do you want to enter?\n");
scanf("%d", &strs);
printf("What is the max size of the strings?\n");
scanf("%d", &size);
array2 = malloc(sizeof(char*)*strs);
cnt = 0;
while (cnt < strs) {
c = 0;
printf("Enter string %d:\n", cnt + 1);
array2[cnt] = malloc(sizeof(char)*size);
scanf("%s", array2[cnt]);
cnt += 1;
}
printf("What letter?\n");
scanf(" %c", &letter);
removeOccurences2(array2,strs,size,letter);
}
Thanks in advance!
You can remove letters from a string in place, because you can only shorten the string.
The code could simply be:
void removeOccurences2(char** letters, int strs, int size, char letter){
int i,j,k;
// loop over the array of strings
for(i=0;i < strs; i++){
// loop per string
for(j = 0, k=0; j < size; j++) {
// stop on the first null character
if (letters[i][j] == '\0'){
letters[i][k] = 0;
break;
}
// If the letter does not match, keep the letter
if(letter != letters[i][j]){
letters[i][k++] = letters[i][j];
}
}
//now print the new string
printf("%s\n", letters[i]);
}
return;
}
But you should free all the allocated arrays before returning to environment, and explicitely return 0 at the end of main.
Well, there are several issues on your program, basically you are getting segmentation fault error because you are accessing invalid memory which isn't allocated by your program. Here are some issues I found:
shiftAmt isn't reset after processing/checking each string which lead to incorrect value of shiftArray.
Values of shiftArray only set as expected for length of string but after that (values from from length of each string to size) are random numbers.
The logic to delete occurrence character is incorrect - you need to shift the whole string after the occurrence character to the left not just manipulating a single character like what you are doing.
1 & 2 cause the segmentation fault error (crash the program) because it causes this line letters[i][j - shiftArray[i][j]] = letters[i][j]; access to unexpected memory. You can take a look at my edited version of your removeOccurences2 method for reference:
int removeOccurences2(char* string, char letter) {
if(!string) return -1;
int i = 0;
while (*(string+i) != '\0') {
if (*(string+i) == letter) {
memmove(string + i, string + i + 1, strlen(string + i + 1));
string[strlen(string) - 1] = '\0'; // delete last character
}
i++;
}
return 0;
}
It's just an example and there is still some flaw in its logics waiting for you to complete. Hint: try the case: "bananaaaa123"
Happy coding!
"...if the string contains a certain character, if so remove all occurrences then shift over the empty positions."
The original string can be edited in place by incrementing two pointers initially containing the same content. The following illustrates.:
void remove_all_chars(char* str, char c)
{
char *pr = str://pointer read
char *pw = str;//pointer write
while(*pr)
{
*pw = *pr++;
pw += (*pw != c);//increment pw only if current position == c
}
*pw = '\0';//terminate to mark last position of modified string
}
This is the cleanest, simplest form I have seen for doing this task. Credit goes to this answer.
The objective of my assignment is to take in user input string and then print out the English alphabetic characters (both lower case and upper case) that the user has entered.
For example if the user inputs:D_!an!_ i12el the output would be Daniel.
My approach was to loop through the input and just remove all the non alpha characters but I dont know how to.Please help with any ideas! This is what I have so far:
#include <stdio.h>
#include <string.h>
int main()
{
char my_array[100];
printf("Enter a message: ");;
while(strlen(gets (my_array)) == 0);
printf(" Your message is: %s\n", my_array);
for(int i = 0; i< strlen(my_array);i++)
{
if(my_array[i] < 'A' || my_array[i] > 'z')
{
my_array[i] = ' ';
}
}
printf(" Your new message is: %s\n", my_array);
}
EDIT:I got my loop working to print out only the alpha characters but it keeps adding extra characters when i print the elements. For example D_!a_*&Ni#32el becomes DaNielASCIIV. I dont know why this is happening.
for(int i = 0; i< 100;i++)
{
if (isalpha(message[i]))
{
putchar(message[i]);
}
}
Rather than trying to update the string you have, just print out a character if it's a letter.
Also, upper case and lower case characters don't immediately follow one another, so you need to check for them separately:
printf(" Your new message is: ");
for(int i = 0; i< strlen(my_array);i++)
{
if((my_array[i] >= 'A' && my_array[i] <= 'Z') ||
(my_array[i] >= 'z' && my_array[i] <= 'z'))
{
putchar(my_array[i]);
}
}
printf("\n");
Alternetely, you could replace the above if condition with a function that checks for this:
if (isalpha(my_array[i]))
EDIT:
The reason you're now seeing extra characters is because you changed the loop to loop over the entire array instead of the length of the string. Go back to using strlen(my_array) instead of 100 and you'll be fine.
Use this pattern for removing elements from an array
int i, j;
j = 0;
for (i=0;i<N;i++)
if (good(array[i]) )
array[j++] = array[i];
N = j;
We go through, adding everything that matches. It's efficient and in-place.
It might be better to loop through the input string and use strchr() to see if the characters are in the string "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz". This has the advantages of not relying on a specific ordering for of the letters of the alphabet (see here and here), and being flexible so that you can easily change the characters that you want to pick out. You could then collect the results in a string, or print the filtered characters out directly.
char my_array[100];
char filtered_array[100];
char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
char *pchar;
int j = 0;
...
for (int i = 0; i < strlen(my_array); i++)
if ((pchar = strchr(alphabet, my_array[i])) != NULL) {
filtered_array[j] = *pchar;
++j;
}
filtered_array[j] = '\0';
...
The above code collects the results in a string. Note that a null-terminator is added to the end of filtered_array[], since this character would not be copied to the new array. If you want to include spaces or hyphens in the filtered string, just add these characters to the alphabet[] string.