My assignment is to write a C program, in which user inputs a sentence, and the program checks if there are words that begin and end with the same letter (for example eye, roar, sos etc.)
I wrote this and I am not sure it will work
I've also got an error: uninitialized local variable 'p2' used. May someone say where I should initialize it?
Maybe someone can add some tips for improving?
#include <stdio.h>
#include<stdlib.h>
#include <string.h>
#define MAX 100
int main()
{
system("chcp 1251");
char arr[MAX];
char* p1, *p2;
int sym, i;
printf("\n\t Enter your sentence(use .(dot) or Enter to finish input):");
while ((sym = getchar()) != '.' && sym != '\n' && i < MAX)
{
arr[i++] = sym; //symbols to array
arr[i] = '0';
}
p1 = arr; //pointer for 1st symbol
for (i = 0; i < MAX; i++)
{
if (arr[i] == ',' || arr[i] == ' ') //finding a word
{
*p2 = arr[i--];
if (*p1 = *p2) //if first and last letters are equal
{
printf("%s", arr);
}
if (arr[i++] == ',' || arr[i++] == ' ')
{
*p1 = arr[i + 2];
}
*p1 = arr[i++];
}
}
return 0;
}```
The variable i should be initialized, i = 0; otherwise i starts from some random value. You can just use fgets to read input, then use strcspn to remove the last \n character.
*p2 = arr[i--];
p2 is declared as a pointer and again is not initialized. It's pointing to some random address in memory and should not be dereferenced yet.
If you are not experienced enough with pointers, you can just use the array style indexing.
for (i = 0; i < MAX; i++)...
MAX is the maximum number of characters which can be stored in arr. But string's length can be less, it's determined by strlen. Example:
char arr[MAX];
printf("input:");
fgets(arr, sizeof(arr), stdin);
arr[strcspn(arr, "\n")] = 0;
size_t len = strlen(arr);
if(len == 0) return 0;
if (arr[0] == arr[len - 1])
printf("first and last match");
else
printf("first and last don't match");
If there are more than one word in arr, you can use strtok to break arr in to words, check each word individually.
Related
I'm currently struggling with counting the occurrences of the words within an inputted string. I believe it is just my logic that is off but I've been scratching my head for a while and I've just hit a wall.
The problems I'm currently yet to solve are:
With longer inputs the ends of the string is sometimes cut off.
Incrementing the counter for each word when repeated
I know the code has things that may not be the most ideal way for it to work but I'm fairly new to C so any pointers are really helpful.
To sum it up I'm looking for pointers to help solve the issues I'm facing above
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#define MAX_WORDS 1000
int main(void) {
int i,j,isUnique,uniqueLen;
char word[MAX_WORDS];
char words[200][30];
char uniqueWords[200][30];
int count[200];
char *p = strtok(word, " ");
int index=0;
//read input until EOF is reached
scanf("%[^EOF]", word);
//initialize count array
for (i = 0; i < 200; i++) {
count[i] = 0;
}
//convert lower case letters to upper
for (i = 0; word[i] != '\0'; i++) {
if (word[i] >= 'a' && word[i] <= 'z') {
word[i] = word[i] - 32;
}
}
//Split work string into an array and save each token into the array words
p = strtok(word, " ,.;!\n");
while (p != NULL)
{
strcpy(words[index], p);
p = strtok(NULL, " ,.;!\n");
index++;
}
/*
Check each string in the array word for occurances within the uniqueWords array. If it is unique then
copy the string from word into the unique word array. Otherwise the counter for the repeated word is incremented.
*/
uniqueLen = 0;
for (i = 0; i < index; i++) {
isUnique = 1;
for (j = 0; j < index; j++) {
if (strcmp(uniqueWords[j],words[i])==0) {
isUnique = 0;
break;
}
else {
}
}
if (isUnique) {
strcpy(uniqueWords[uniqueLen], words[i]);
count[uniqueLen] += 1;
uniqueLen++;
}
else {
}
}
for (i = 0; i < uniqueLen; i++) {
printf("%s => %i\n", uniqueWords[i],count[i]);
}
}
This is the code i ended up using, this turned out to be mainly an issue with using the scanf function. Placing it in a while loop made it much easier to edit words as inputted.
Thankyou for all the help :)
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
int main(void) {
// Create all variables
int i, len, isUnique, index;
char word[200];
char uniqueWords[200][30];
int count[200];
// Initialize the count array
for (i = 0; i < 200; i++) {
count[i] = 0;
}
// Set the value for index to 0
index = 0;
// Read all words inputted until the EOF marker is reached
while (scanf("%s", word) != EOF) {
/*
For each word being read if the characters within it are lowercase
then each are then incremented into being uppercase values.
*/
for (i = 0; word[i] != '\0'; i++) {
if (word[i] >= 'a' && word[i] <= 'z') {
word[i] = word[i] - 32;
}
}
/*
We use len to find the length of the word being read. This is then used
to access the final character of the word and remove it if it is not an
alphabetic character.
*/
len = strlen(word);
if (ispunct(word[len - 1]))
word[len - 1] = '\0';
/*
The next part removes the non alphabetic characters from within the words.
This happens by incrementing through each character of the word and by
using the isalpha and removing the characters if they are not alphabetic
characters.
*/
size_t pos = 0;
for (char *p = word; *p; ++p)
if (isalpha(*p))
word[pos++] = *p;
word[pos] = '\0';
/*
We set the isUnique value to 1 as upon comparing the arrays later we
change this value to 0 to show the word is not unique.
*/
isUnique = 1;
/*
For each word through the string we use a for loop when the counter i
is below the index and while the isUnique value is 1.
*/
for (i = 0; i < index && isUnique; i++)
{
/*
Using the strcmp function we are able to check if the word in
question is in the uniqueWords array. If it is found we then
change the isUnique value to 0 to show that the value is not
unique and prevent the loop happening again.
*/
if (strcmp(uniqueWords[i], word) == 0)
isUnique = 0;
}
/* If word is unique then add it to the uniqueWords list
and increment index. Otherwise increment occurrence
count of current word.
*/
if (isUnique)
{
strcpy(uniqueWords[index], word);
count[index]++;
index++;
}
else
{
count[i - 1]++;
}
}
/*
For each item in the uniqueWords list we iterate through the words
and print them out in the correct format with the word and the following count of them.
*/
for (i = 0; i < index; i++)
{
printf("%s => %d\n", uniqueWords[i], count[i]);
}
}
I don't know if you are facing some requirements, but for all it's limitations in terms of standard library functions, C does have one that would make your job much easier, strstr, e.g.:
Live demo
#include <stdio.h>
#include <string.h>
int main() {
const char str[] = "stringstringdstringdstringadasstringipoistring";
const char* substr = "string";
const char* orig = str;
const char* temp = substr;
int length = 0;
while(*temp++){length++;} // length of substr
int count = 0;
char *ret = strstr(orig, substr);
while (ret != NULL){
count++;
//check next occurence
ret = strstr(ret + length, substr);
}
printf("%d", count);
}
The output should be 6.
Regarding user3121023's comment, scanf("%999[^\n]", word); parses all characters until it finds a \n or it reaches the width limit, and I agree fgets ( word, sizeof word, stdin); is better.
First time asking a question here:
well I need to take the original string
and remove the spaces and numbers from the string
I need to use the exact amount of memory.
For some reason, the string is fine in the beginning
but then it prints garbage values:
original string: "abcd2 34fty 78 jurt#"
what needed to be done: abcdftyjurt#
My code:
#define _CRT_SECURE_NO_WARNINGS
#include <malloc.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
/* Function declarations */
/*-------------------------------------------------------------*/
void Ex1();
char* clearDigitsAndSpaces(char*);
/*-------------------------------------------------------------*/
void Ex2();
/*-------------------------------------------------------------*/
void Ex3();
/*-------------------------------------------------------------*/
/* Declarations of other functions */
int main() {
int select = 0, i, all_Ex_in_loop = 0;
printf("Run menu once or cyclically?\n(Once - enter 0, cyclically - enter other number) ");
if (scanf("%d", &all_Ex_in_loop) == 1)
do {
for (i = 1; i <= 3; i++)
printf("Ex%d--->%d\n", i, i);
printf("EXIT-->0\n");
do {
select = 0;
printf("please select 0-3 : ");
scanf("%d", &select);
} while ((select < 0) || (select > 3));
switch (select) {
case 1: Ex1(); break;
case 2: Ex2(); break;
case 3: Ex3(); break;
}
} while (all_Ex_in_loop && select);
return 0;
}
/* Function definitions */
void Ex1() {
char input[] = "abcd2 34fty 78 jurt#";
char *temp = NULL;
temp = clearDigitsAndSpaces(input);
printf("%s\n ", temp);
free(temp);
}
char *clearDigitsAndSpaces(char *old_string) {
char *new_string;
int count = 0;
int i = 0;
int j = 0;
int size = strlen(old_string);
new_string = (char *)malloc(size * sizeof(char));
assert(new_string); /*Memory allocation check*/
while (old_string[i]) {
if (old_string[i] != ' ' && (old_string[i] > '9' || old_string[i] < '0')) {
new_string[j++] = old_string[i];
} else {
//size -= 1;
new_string = (char *)realloc(new_string, size - 1);
}
i++;
}
assert(new_string);
//printf("%s", new_string);
return new_string;
}
void Ex2() {
}
void Ex3() {
}
The problem in your code is you must allocate one extra byte for the null terminator.
You can avoid using realloc() by first scanning the source string to determine the allocation size and then use a separate loop to copy the contents:
char *clearDigitsAndSpaces(const char *src) {
char *new_string;
size_t size = 1; // 1 extra byte for the null terminator.
for (size_t i = 0; src[i] != '\0'; i++) {
if (src[i] != ' ' && !(src[i] >= '0' && src[i] <= '9'))
size++;
}
new_string = malloc(size);
if (new_string) {
size_t j = 0;
for (size_t i = 0; src[i] != '\0'; i++) {
if (src[i] != ' ' && !(src[i] >= '0' && src[i] <= '9'))
new_string[j++] = src[i];
}
new_string[j] = '\0'; // set the null terminator
}
return new_string;
}
Firstly: you need to understand the difference between the length of a C-string and the size of a C-string. The length does not include the null terminator. The size does. So this snippet:
int size = strlen(old_string);
new_string = (char*)malloc(size * sizeof(char));
needs to be
int size = strlen(old_string) + 1;
new_string = (char*)malloc(size * sizeof(char));
(note that if you're using Unicode in Windows, with wchar_t instead of char, then the size in bytes is twice the length, plus 2 - each character is two bytes, as well as the null terminator aka 'sentinel')
Secondly: I would suggest you use parenthesis to be explicit about intention. It may not be "absolutely necessary", but there would be no doubt about the intention when someone else reads your code. Also avoid indexing the same thing repeatedly. Change:
if (old_string[i]!=' ' && (old_string[i] > '9' || old_string[i]< '0'))
to:
char oldChar = old_string[i];
if ((oldChar != ' ')
&& ((oldChar > '9') || (oldChar < '0'))
)
Finally, you need to emplace a null character at the end. You don't need to realloc; just use not all of the buffer. Change:
new_string = (char*)realloc(new_string, size-1);
to:
new_string[j++] = '\0';
// PS: if you really want to realloc, then add "new_string = (char*)realloc(new_string, j);" after writing the null character.
Also - if you change the malloc to a calloc, you won't need to write a null terminator, since the entire buffer would be nulled before you copied anything to it.
Furthermore, I would add a defensive limit check to i in the while loop to ensure it cannot go on ad-infinitum.
I'm quite new to C and I'm wondering why in the code below, the char I'm comparing to each letter of the string word is showing that it's equal everytime.
For example
If I've inputted the word
apple
and I'm looking for any repeating char in "apple" my function. I pass in to the function each char of apple such as a, p, p etc. It should return 1 when I pass in p since it's repeated, but instead, for every char of apple, my function says a == word[0], a == word[1] even though word[1] for "apple" is 'p'.
I know char is ASCII, so each char has a number value, but I'm not sure why this is not working. Perhaps, I'm using the pointer *word in the functions arguments incorrectly?
My code is below for my function, rpt_letter:
int rpt_letter(char *word, char c)
{
int i;
int count = 0;
i = 0;
printf("This is the WORD %s\n", word);
while(count < 2)
{
if(word[i] == c)
{
count++;
printf("the count is %d\n the char is %c and the string is %c\n", count, c, word[i]);
}
i++;
}
if (count<2)
{
// printf("letter %c was not found in the array. \n", c);
return 0;
}
else
{
//printf("letter %c was found at index %d in the array.\n", c, mid);
repeats[rpt_counter] = c;
rpt_counter++;
return 1;
}
return 0;
}
I'll include the main method just in case -- but I believe the main method is working well
int main(void)
{
//! showArray(list, cursors=[ia, ib, mid])
//int n = 51;
char word[51];
scanf("%s", word);
//length of string
for (n=0; word[n] != '\0'; n++); //calculate length of String
printf("Length of the string: %i\n", n);
int count = 0;
//sort words
int i;
char swap = ' ';
for(int k = 0; k < n; k++)
{
for (i=0; i<n-1; i++)
{
//if prev char bigger then next char
if (word[i] > word[i+1])
{
//make swap = prev char
swap = word[i];
//switch prev char with next char
word[i] = word[i+1];
//make next letter char
word[i+1] = swap;
}
}
}
printf("%s\n", word);
for (i=0; i<n-1; i++)
{
int rpt = rpt_letter(word, word[i]);
if(rpt == 1)
{
count++;
}
}
printf("%d", count);
return 0;
}
I've tried a number of things such as using the operator !=, also <, > but it gives me the same result that each word[ia] == c.
You are getting this issue because in your code rpt_letter() the while loop has a terminating condition count >= 2. Now consider input apple and character a. As a appears in apple only once, the count after traversing the whole word remains 1. But the loop doesn't terminate. So, the index i becomes greater than the length of string and tries to check the character appearing after that.
The loop terminates eventually when it gets another a this way. You need to add a check for the terminating null character in your loop so that it doesn't cross the length of the string .
Change the while loop condition to something like -
while((count < 2) && (word[i] != '\0'))
My assignment is to allow the user to enter any input and print the occurrences of letters and words, we also have to print out how many one letter, two, three, etc.. letter words are in the string. I have gotten the letter part of my code to work and have revised my word function several times, but still can't get the word finding function to even begin to work. The compiler says the char pointer word is undeclared when it clearly is. Do I have to allocate memory to it and the array of characters?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void findLetters(char *ptr);
void findWords(char *point);
int main()
{
char textStream[100]; //up to 98 characters and '\n\ and '\0'
printf("enter some text\n");
if (fgets(textStream, sizeof (textStream), stdin)) //input up to 99 characters
{
findLetters(textStream);
findWords(textStream);
}
else
{
printf("fgets failed\n");
}
return 0;
}
void findLetters(char *ptr) //find occurences of all letters
{
int upLetters[26];
int loLetters[26];
int i;
int index;
for (i = 0; i < 26; i++) // set array to all zero
{
upLetters[i] = 0;
loLetters[i] = 0;
}
i = 0;
while (ptr[i] != '\0') // loop until prt[i] is '\0'
{
if (ptr[i] >= 'A' && ptr[i] <= 'Z') //stores occurrences of uppercase letters
{
index = ptr[i] - 'A';// subtract 'A' to get index 0-25
upLetters[index]++;//add one
}
if (ptr[i] >= 'a' && ptr[i] <= 'z') //stores occurrences of lowercase letters
{
index = ptr[i] - 'a';//subtract 'a' to get index 0-25
loLetters[index]++;//add one
}
i++;//next character in ptr
}
printf("Number of Occurrences of Uppercase letters\n\n");
for (i = 0; i < 26; i++)//loop through 0 to 25
{
if (upLetters[i] > 0)
{
printf("%c : \t%d\n", (char)(i + 'A'), upLetters[i]);
// add 'A' to go from an index back to a character
}
}
printf("\n");
printf("Number of Occurrences of Lowercase letters\n\n");
for (i = 0; i < 26; i++)
{
if (loLetters[i] > 0)
{
printf("%c : \t%d\n", (char)(i + 'a'), loLetters[i]);
// add 'a' to go back from an index to a character
}
}
printf("\n");
}
void findWords(char *point)
{
int i = 0;
int k = 0;
int count = 0;
int j = 0;
int space = 0;
int c = 0;
char *word[50];
char word1[50][100];
char* delim = "{ } . , ( ) ";
for (i = 0; i< sizeof(point); i++) //counts # of spaces between words
{
if ((point[i] == ' ') || (point[i] == ',') || (point[i] == '.'))
{
space++;
}
}
char *words = strtok(point, delim);
for(;k <= space; k++)
{
word[k] = malloc((words+1) * sizeof(*words));
}
while (words != NULL)
{
printf("%s\n",words);
strcpy(words, word[j++]);
words = strtok(NULL, delim);
}
free(words);
}
This is because you are trying to multiply the pointer position+1 by the size of pointer. Change line 100 to:
word[k] = malloc(strlen(words)+1);
This will solve your compilation problem, but you still have other problems.
You've got a couple of problems in function findWords:
Here,
for (i = 0; i< sizeof(point); i++)
sizeof(point) is the same as sizeof(char*) as point in a char* in the function fincdWords. This is not what you want. Use
for (i = 0; i < strlen(point); i++)
instead. But this might be slow as strlen will be called in every iteration. So I suggest
int len = strlen(point);
for (i = 0; i < len; i++)
The same problem lies here too:
word[k] = malloc((words+1) * sizeof(*words));
It doesn't makes sense what you are trying with (words+1). I think you want
word[k] = malloc( strlen(words) + 1 ); //+1 for the NUL-terminator
You got the arguments all mixed up:
strcpy(words, word[j++]);
You actually wanted
strcpy(word[j++], words);
which copies the contents of words to word[j++].
Here:
free(words);
words was never allocated memory. Since you free a pointer that has not been returned by malloc/calloc/realloc, the code exhibits Undefined Behavior. So, remove that.
You allocated memory for each element of word. So free it using
for(k = 0; k <= space; k++)
{
free(word[k]);
}
Your calculation of the pointer position+1 is wrong. If you want the compilation problem will go away change line 100 to:
word[k] = malloc( 1 + strlen(words));
Alright this is a homework question whereby I can't use the string.h library. This function is to copy not more than n characters (characters that
follow a null character are not copied) from the array pointed to by s2 to the array pointed to by s1.
int main()
{
char sourceString[100];
char targetString[100];
int num;
printf("Enter a string:");
gets(sourceString);
printf("Enter no. of characters: ");
scanf("%d", &num);
printf("stringncpy(): %s", stringncpy(targetString, sourceString, num));
}
char *stringncpy(char * s1, char * s2, int n)
{
int i;
for (i = 0; i < n; i++)
{
if (s2[i] != '\0')
{
s1[i] = s2[i];
}
else
{
break;
}
}
s1[i] = '\0';
return s1;
}
It runs fine except that it is printing some rubbish unrecognizable characters after n characters. Apprantly running the code with http://ideone.com/, I don't get those rubbish characters but on VS it does.
Because gets is used it is better to use
if (s2[i] != '\0' && s2 [i] != '\n')
instead if
if (s2[i] != '\0')
And if n define the max numer of character you should ensure that n < 100. When after for loop i == n writing '\0' to i-th position can cause a problem. Or maybe loop should be
for (i = 0; i < n-1; i++)