Simple C program involving arrays cannot execute - c

I have a homework problem which requires me to convert a word a user entered to Pig Latin by moving the first letter of the word to the end and adding an ay to it. For example, Tuesday becomes uesdayTay. This process should be repeated until the user types STOP.
I'm really new to arrays, so I might be using them wrongly, but I can't find out why. The program I wrote can be compiled but crashes whenever I execute it. I'm sure this program is rather simple, but here is my code:
#include <stdio.h>
#include <string.h>
int main ()
{
char *input_word [100], *temp [100], *stop [4];
int n = 0;
printf("Enter a word: ");
for( n = 0; n < 100; n++)
{
scanf("%s", input_word[n]);
}
while ( strcmp ( stop [4], "STOP" ) != 0 )
{
*temp = input_word [0];
for ( int j = 1; j <= n-1; j++)
{
*input_word [j-1] = *input_word [j];
}
input_word [n-1] = *temp;
printf("%s", *input_word);
printf("ay\n");
printf("Type STOP to terminate: ");
for ( n = 0; n < 4; n++ )
{
scanf("%s", stop[n] );
}
}
return 0;
}
Can anyone please help me out? I find arrays to be rather confusing. Thanks!

scanf("%s", input_word[n])
I will stop you already there.
You declared input_word as an array of pointers, but those pointers are 1. not initialized 2. not pointing to valid memory that you need to allocate.
Instead first declare an array to hold the input from the user
char input_word[100];
Now to keep things simple, use fgets to read from the command line
fgets(input_word, sizeof(input_word), stdin);
Now remove the trailing \n if any:
char* p = strchr(input_word, '\n');
if (p)
{
*p = '\0';
}
Now you have "Tuesday\0" (if you entered that word) in input_word.
Have another array for the new word:
char output_word[100] = { '\0' };
Skip the first character and copy until end of string:
strcpy(output_word, input_word + 1);
Now take the first character and add it:
strncat(output_word, input_word, 1);
Then add the rest using strcat, and sprinkle code with checks like length of string entered.

Related

i have a problem with strcat into 2d array in c

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!

Reversing String Only Using For Loop

I have been trying to reverse(and print it that way) a given string only using for loops and nothing more. I think I have built up the basic logic, but it has some defects. When run, it only reverses the first two characters and then stops. Please help me find the defect in my logic.
#include<stdio.h>
#include<stdlib.h>
int main()
{
char a[20];
int i;
printf("Enter any String\n");
gets(a);
for(i=0;a[i]!=NULL;i++)
{}
for(i=1;i>=0;i--)
{
printf("%c",a[i]);
}
}
For starters the function gets is not a standard C function any more. it is unsafe. Instead use the standard C function fgets. The function can append the new line character '\n' to the entered string that should be excluded from the string.
It is unclear from your question whether you are allowed to use standard string functions.
Nevertheless here is a demonstrative program that does the task without using standard C string functions and that uses only for loops (neither while loop nor do-while loop).
#include <stdio.h>
int main(void)
{
enum { N = 20 };
char s[N];
printf( "Enter any String less than %d symbols: ", N );
fgets( s, N, stdin );
// remove the new line character and calculate the length of the string
size_t n = 0;
for ( ; s[n] != '\0' && s[n] != '\n'; ) ++n;
s[n] = '\0';
// reverse the string
for ( size_t i = 0; i < n / 2; i++ )
{
char c = s[i];
s[i] = s[n-i-1];
s[n-i-1] = c;
}
puts( s );
return 0;
}
Its output might look the following way
Enter any String less than 20 symbols: Hello dev.aniruddha
ahddurina.ved olleH
If you want just to output the original string in the reverse order then the program can look like
#include <stdio.h>
int main(void)
{
enum { N = 20 };
char s[N];
printf( "Enter any String less than %d symbols: ", N );
fgets( s, N, stdin );
// remove the new line character and calculate the length of the string
size_t n = 0;
for ( ; s[n] != '\0' && s[n] != '\n'; ) ++n;
s[n] = '\0';
// reverse the string
for ( ; n-- != 0; )
{
putchar( s[n] );
}
putchar( '\n' );
return 0;
}
Its output is the same as shown above
Enter any String less than 20 symbols: Hello dev.aniruddha
ahddurina.ved olleH
gets() is a bad idea as you can easily get overflows and it is no longer part of the c standard.
So let's assume that the string entered fits the array and this is just for an excercise with no reallife usage.
Your first loop finds the terminator. That's good.
Your second loop sets the variable that indicates the terminator to 1, destroying the result.
If you remove the assignment i=1, your program compiles with gcc and does what you want.
#include<stdio.h>
#include<stdlib.h>
int main()
{
char a[20];
int i;
printf("Enter any String\n");
gets(a);
for(i=0;a[i]!=NULL;i++)
{}
for(;i>=0;i--) //removed i=1 here
{
printf("%c",a[i]);
}
}
But there are still some issues to be addressed.
You will also reverse the terminator, instead you should start from i-1
I would advise to not use a for loop if you do not have a counter criterion The first loop should rather be a while loop, but as it was part of the assignment you had no choice still I will replace it in my recommendation. As they can easily be swapped.
Then you could use another variable for the second loop for clarity.
Also NULL is the NULL-pointer not the value 0 (also namend NUL apperantly) . So you should replace this either with 0 or with '\0'
Also stdlib.h is not required here
#include<stdio.h>
int main()
{
char a[20];
int i = 0;
printf("Enter any String\n");
gets(a);
while (a[i] != 0)
{
i++;
}
for(int j = i-1; j>=0; j--) // -1 to get the value in front of the terminator
{
printf("%c",a[j]);
}
printf("\n"); //to flush the output.
}
Here is the solution code.
The first for loop is to be used for determining the length of the string and the second for loop is for traversing the string from the last position to the first.
#include<stdio.h>
int main()
{
char a[20];
int i,j,len;
printf("Enter a String\n");
gets(a);
for(i=0;a[i]!=NULL;i++)
{}
len=i;
for(j=len-1;j>=0;j--)
{
printf("%c",a[j]);
}
}
I think why only two chars are been return is because of the condition statement in your second "for loop".
for(i=1;i>=0;i--)
Note:
it repeats from 1~0 (1,0): meaning it will repeat only twice
first iteration: when i == 1
second iteration: when i == 0 ; then it ends .
Please note that you created two "for loops" with the first one having no content.
Bonus:
I tried to fixed your code but realized that my C language skills isnt the best lol . Anyways, i came up with something that you could reference but it only reverse strings of less than 8 elements.
#include<stdio.h>
#include<stdlib.h>
int findlength(char a[]);
int main()
{
char a[20];
int i;
printf("Enter any String\n");
gets(a);
int len = findlength(a);
printf("Lenght of the String is: %d \n",len);
printf("Reversed String is: ");
for(i=len;i>-1;i--){
printf("%c",a[i]);
}
}
int findlength(char a[]){
int result = 0;
int i;
for(i=0;i<sizeof(a) / sizeof(char);i++){ // sizeof(char) is 1
if(a[i] == '\0') //end of string
return result;
result += 1;
}
return result;
}

Manipulating dynamically allocated 2D char arrays in C

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.

Reversing a string word by word

I'm trying to write a program that reverses a string inputted by the user.
Enter a sentence: you can cage a swallow can't you
Reversal of sentence: you can't swallow a cage can you
So I thought about scanning for the string character by character. Then copying the string from the end to the beginning into a new string. At this point, I know that I've got a new word every time I see a space, so I have to invert the order of the letters that are between two spaces. Here's my code:
#include <stdio.h>
#include <string.h>
int main(){
char sentence[64], reversal[64], reversal_copy[64];
int i = 0, index = 0;
printf("Enter a sentence: ");
while(sentence[strlen(sentence)-1]!= '\n'){
scanf("%c", &sentence[i]);
i++;
}
printf("Reversal of sencente: ");
for(int h = strlen(sentence) - 2, k = 0; h >= 0; h++, k++){
reversal[k] = sentence[h];
strcpy(reversal_copy, reversal);
if(sentence[h] == ' '){
for(int m = h; m >= index && m <= h; m--, index++){
reversal[m] = reversal_copy[index];
}
}
}
printf("Reversal of sentence: %s\n\n", reversal);
return 0;
}
I get a segmentation fault error and I believe it happens around here:
for(int h = strlen(sentence) - 2, k = 0; h >= 0; h++, k++){
reversal[k] = sentence[h];
but I don't quite get why. Could you help me with this?
The condition for your first loop to continue is h >= 0, and as you are incrementing h each time this is going to keep getting bigger until it exceeds the size of sentence and throws the error.
If your intention for that loop is to work backwards through sentence then I think you should decrement h and k (h--, k--), but if the intention is to work forwards through sentence then your condition needs to be changed so that the loop finishes once h has reached the end of sentence
The word order can be reversed using a recursive function.
#include <stdio.h>
#include <string.h>
void reverse ( char *str, char *original) {
char temp[strlen ( str) + 1];
temp[0] = 0;
int offset = 0;
if ( 1 == sscanf ( str, "%s%n", temp, &offset)) {
reverse ( str + offset, original);//recursive call
}
else {//at the end of the original string
*original = 0;//set zero at first character
return;
}
//as recursion unwinds, concatenate the words
strcat ( original, temp);
if ( str != original) {//will be false when unwinds reaches first iteration
strcat ( original, " ");
}
return;
}
int main( void) {
char text[] = "you can cage a swallow can't you";
printf ( "%s\n", text);
reverse ( text, text);
printf ( "%s\n", text);
return 0;
}
For starters:
During the while-loop's 1st iteration strlen() is called on an un-initialised variable. This invokes undefined behaviour. Anything can happen.
In any case of updating a char-array character by character you completely ignore the fact that a 0-terminator is necessary to make a char-array a C-string. Only a C-string may be passed to (most of the) str*() functions.
Also scanf() might fail. Test for this.

Program that checks if an array is a palindrome

I'm trying to create a program that checks if a given array/string is a palindrome or not and its not working. The program just prints "0" on every given array, even on palindromes.
int main()
{
char string[100]= {0};
char stringReverse[100]= {0};
int temp = 0;
int firstLetter = 0;
int lastLetter = 0;
printf("Please enter a word or a sentence: ");
fgets(string, 100, stdin);
strcpy(stringReverse , string); // This function copies the scanned array to a new array called "stringReverse"
firstLetter = 0;
lastLetter = strlen(string) - 1; //because in array, the last cell is NULL
// This while reverses the array and insert it to a new array called "stringReverse"
while(firstLetter < lastLetter)
{
temp = stringReverse[firstLetter];
stringReverse[firstLetter] = stringReverse[lastLetter];
stringReverse[lastLetter] = temp;
firstLetter++;
lastLetter--;
}
printf("%s %s", stringReverse, string);
if ( strcmp(stringReverse , string) == 0)
{
printf("1");
}
else
{
printf("0");
}
}
Lets say we implement a simple fun to do that
int check_palindrome (const char *s) {
int i,j;
for (i=0,j=strlen(s)-1 ; i<j ; ++i, --j) {
if (s[i] != s[j]) return 0; // Not palindrome
}
return 1; //Palindrome
}
I think this is far more simpler ;)
For the code posted in question:
Be aware of fgets(). It stops in the first '\n' or EOF and keeps the '\n' character.
So if you give radar for ex, the result string will be "radar\n", which doesn't match with "\nradar"
The Problem:
Let's say you enter the string RACECAR as input for your program and press enter, this puts a newline character or a '\n' in your buffer stream and this is also read as part of your string by fgets, and so your program effectively ends up checking if RACECAR\n is a palindrome, which it is not.
The Solution:
After you initialize lastLetter to strlen(string) - 1 check if the last character in your string (or the character at the lastLetter index is the newline character (\n) and if so, decrease lastLetter by one so that your program checks if the rest of your string (RACECAR) is a palindrome.
lastLetter = strlen(string) - 1; //because in array, the last cell is NULL
// Add these 2 lines to your code
// Checks if the last character of the string read by fgets is newline
if (string[lastLetter] == '\n')
lastLetter--;
fgets adds a '\n' at the end.
So if the user entered "aba", string contains "aba\n".
reverseString contains "\naba".
So it doesn't match.
After the fgets, add this code
int l = strlen(string) - 1;
string[l] = 0;
This will strip out the '\n' at the end before copying it to reverseString.
That aside, you can do this whole program inplace without the need of a second buffer or strcpy or strlen calls.
You have several issues in your code:
first you forgot the last closing brace };
then you forgot to remove the trailing \n (or maybe also \r under Windows) in string;
you don't need to revert the string into a new string; a one-pass check is enough:
Here is a working code:
#include <stdio.h>
#include <string.h>
int main()
{
char string[100]= {0};
int temp = 0;
int firstLetter = 0;
int lastLetter = 0;
printf("Please enter a word or a sentence: ");
fgets(string, 100, stdin);
firstLetter = 0;
lastLetter = strlen(string) - 1; //because in array, the last cell is NULL
while ((string[lastLetter]=='\n')||(string[lastLetter]=='\r')) {
lastLetter--;
}
// This while reverses the array and insert it to a new array called "stringReverse"
temp = 1;
while(firstLetter < lastLetter)
{
if (string[firstLetter] != string[lastLetter]) {
temp = 0;
break;
}
firstLetter++;
lastLetter--;
}
if ( temp )
{
printf("1");
}
else
{
printf("0");
}
}
You can do it by this simpleway also.
#include <stdio.h>
#include <string.h>
int main()
{
char string[10], revString[10];
printf("Enter string for reversing it...\n");
scanf("%s", string);
int stringLength = strlen(string);
for(int i = 0; string[i] != '\0'; i++, stringLength--)
{
revString[i] = string[stringLength - 1];
}
if(strcmp(string, revString) == 0)
printf("Given string is pelindrom\n");
else
printf("Given string is not pelindrom\n");
}
#include<stdio.h>
#include<string.h>`enter code here`
void fun(char *a);
int main ()
{
char p[100];
char *s=p;
printf("enter the string");
scanf("%[^\n]",s);
fun(s);
}
void fun(char *a)
{
if(*a && *a!='\n')
{
fun(a+1);
putchar(*a);
}
}
// use this approach better time complexity and easier work hope this helps

Resources