C storing strings into an array - c

I'm working in a problem from the "C programming a Modern Approach 2nd Edition" text. I want to write a program that writes the smallest and largest words. The program stops accepting inputs when the user enters a 4-letter word.
I'm using an array of strings to solve this but I can't even get my program to store words in it.
#include <stdio.h>
#include <string.h>
#define WORD_LEN 20
int main()
{
char word[WORD_LEN]={0},ch;
char *a[10]={}; //Max 10 words in the array
int i=0,j;
for(;;)
{
printf("Enter a word: ");
fgets(word,WORD_LEN,stdin);
strtok(word, "\n"); //removes newline
a[i] = word;
if(strlen(word) == 4) //if word is 4 characters
break; //break out of loop
i++;
}
for(j=0;j<i;j++) //displaying array
printf("%s\n",a[j]);
return 0;
}
Output:
Enter a word: Analysis
Enter a word: Martin
Enter a word: Jonathan
Enter a word: Dana
Dana
Dana
Dana
Any idea into what I'm doing wrong? Thanks.

As BLUEPIXY mentioned, you are storing same address in all a[i]s. So at the end of the loop, it prints the last output i times.
Solution:
You need to allocate memory for a[i] and copy the strings.
#include <stdio.h>
#include <string.h>
#define WORD_LEN 20
#define MAX_NUM_WORD 10 //Max 10 words in the array
int main()
{
char word[WORD_LEN]={0},ch;
char *a[MAX_NUM_WORD]={0};
int i=0,j;
for(;;)
{
printf("Enter a word: ");
fgets(word,WORD_LEN,stdin);
strtok(word, "\n"); //removes newline
a[i] = malloc(sizeof(char)* (strlen(word)+1)); //1 for '\0'
strcpy(a[i], word);
i++;
if(strlen(word) == 4) //if word is 4 characters
break; //break out of loop
//i++; //You will be missing last 4 letter word if i++ is here.
if(MAX_NUM_WORD <= i) //You can store only MAX_NUM_WORD strings
break;
}
for(j=0;j<i;j++) //displaying array
printf("%s\n",a[j]);
//Your other code.
for(i=0; i<MAX_NUM_WORD && NULL != a[i]; i++)
free(a[i]); //Free the allocated memory.
return 0;
}

Adding to others answers, when using malloc to allocate memory for your strings, it is good to also check the return value of void* pointer returned from it.
Additionally, it is also safe to check the return value of fgets, just to be super safe.
This solution demonstrates these points:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WORD_LEN 20
#define MAX_NUM_WORD 10
#define EXIT_LEN 4
int
main(void) {
char word[WORD_LEN];
char *a[MAX_NUM_WORD];
int i = 0, wrd;
while (i < MAX_NUM_WORD) {
printf("Enter a word: ");
if (fgets(word, WORD_LEN, stdin) != NULL) {
word[strlen(word)-1] = '\0';
}
a[i] = malloc(strlen(word)+1);
if (a[i] == NULL) {
fprintf(stderr, "%s\n", "Malloc Problem");
exit(EXIT_FAILURE);
}
strcpy(a[i], word);
i++;
if (strlen(word) == EXIT_LEN) {
break;
}
}
// Print and free, all at once.
for (wrd = 0; wrd < i; wrd++) {
printf("%s\n", a[wrd]);
free(a[wrd]);
a[wrd] = NULL;
}
return 0;
}

Related

C Program to Check for Palindrome String

I wrote two sample programs to check for a palindrome string. But in both I am getting output like, its not a palindrome number. What I am missing?
I strictly assume somehow code is executing my if statement and put flag in to 1. May be because of that length calculation. Anyone has a better idea?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
int main(void) {
setbuf(stdout,NULL);
char name[100];
int i,length,flag=0,k;
printf("Enter your name");
/*scanf("%s",name);*/
gets(name);
length=strlen(name);
for(i=0;i<=length-1;i++)
{
for(k=length-1;k>=0;k--)
{
if(name[i]!=name[k])
{
flag=1;
break;
}
}
}
if(flag==0)
{
printf("Give word is a palindrome");
}
if(flag==1)
{
printf("This is NOT a palindrome word");
}
return 0;
}
and
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
int main(void) {
setbuf(stdout,NULL);
char name[100];
int i,length,flag=0;
printf("Enter your name");
/*scanf("%s",name);*/
gets(name);
length=strlen(name);
for(i=0;i<=length/2;i++)
{
if(name[i]!=name[length-1])
{
flag=1;
}
}
if(flag==0)
{
printf("Give word is a palindrome");
}
if(flag==1)
{
printf("This is NOT a palindrome word");
}
return 0;
}
First Algorithm
The algorithm you are using in the first program involves comparing each letter to every other letter which does not help in determining if the number is a palindrome and it does not seem fixable.
Second Algorithm
The problem with the second approach, however, is you are always comparing name[i] to name[length]. Instead change it to length-i-1. This will start comparing from length-1 and decrement the length of the character by 1 for every next iteration:
for(i = 0;i <= length / 2;i++)
{
if(name[i] != name[length-i-1])
{
flag=1;
break;
}
}
gets() and buffer overflow
Do not use gets. This method is susceptible to a buffer overflow. If you enter a string longer than 100 characters, it will result in undefined behavior. Use fgets instead for deterministic behavior:
fgets(name, sizeof(name), stdin);
This takes in the size of the buffer and only reads up to sizeof(name) characters.
Full code
Ideally, you should consider wrapping the logic to check if the string is a palindrome in a function:
int is_palindrome(char*);
int main(void)
{
char name[100];
setbuf(stdout,NULL);
printf("Enter your name");
fgets(name, sizeof(name), stdin);
if(is_palindrome(name))
{
printf("The given word is a palindrome");
}
else
{
printf("This is NOT a palindrome word");
}
return 0;
}
int is_palindrome(char* name)
{
int length = strlen(name);
int flag = 0, i;
for(i = 0;i <= length / 2; i++)
{
if(name[i]!=name[length-i-1])
{
return 0;
}
}
return 1;
}
There is plenty wrong with both your attempts. I strongly suggest using a debugger to investigate how your code works (or doesn't).
Your first attempt performs length2 (incorrect) comparisons, when clearly only length / 2 comparisons are required. The second performs length / 2 comparisons but the comparison is incorrect:
name[i] != name[length-1] ;
should be:
name[i] != name[length - i - 1] ;
Finally you iterate exhaustively when you could terminate the comparison as soon as you know they are not palindromic (on first mismatch).
There may be other errors - to be honest I did not look further than the obvious, because there is a better solution.
Suggest:
#include <stdbool.h>
#include <string.h>
bool isPalindrome( const char* str )
{
bool is_palindrome = true ;
size_t rev = strlen( str ) - 1 ;
size_t fwd = 0 ;
while( is_palindrome && fwd < rev )
{
is_palindrome = (str[fwd] == str[rev]) ;
fwd++ ;
rev-- ;
}
return is_palindrome ;
}
In use:
int main()
{
const char* test[] = { "xyyx", "xyayx", "xyxy", "xyaxy" } ;
for( size_t t = 0; t < sizeof(test)/sizeof(*test); t++ )
{
printf("%s : %s palindrome\n", test[t],
isPalindrome( test[t] ) ? "Is" : "Is not" ) ;
}
return 0;
}
Output:
xyyx : Is palindrome
xyayx : Is palindrome
xyxy : Is not palindrome
xyaxy : Is not palindrome
Try this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char text[100];
int begin, middle, end, length = 0;
printf("enter the name: ");
scanf("%s",text);
while ( text[length] != '\0' ){
length++;}
end = length - 1;
middle = length/2;
for ( begin = 0 ; begin < middle ; begin++ ) {
if ( text[begin] != text[end] ) {
printf("Not a palindrome.\n");
break;
}
end--;
}
if( begin == middle )
printf("Palindrome.\n");
return 0;
}
The problem with the first piece of code is you are comparing it more than required, compare it with length-i-1.
The main problem with the second code is you are comparing it with only the last letter of a word.
Hope you understood your mistake

How do I reallocate a array of structures in a function

I am trying to allocate a dynamic array of Country objects for my school project. I have malloc'd the array in main() function and I am reallocating it in a add_country() function. but it seems to give me realloc invalid ponter error. Could someone help? This is the minimal reproducable code.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int count = 0;
typedef struct test_Country
{
char name[20];
int gold;
int silver;
int bronze;
} test_Country;
test_Country *addtest_Country(test_Country test_Country_obj, test_Country*array)
{
int flag = 0;
printf("%s\n", "before realloc");
test_Country *new_array;
new_array = realloc(array, sizeof(test_Country *) * (count + 1));
printf("%s\n", "after realloc");
//array[count].name = (char *)malloc(strlen(test_Country_obj.name) + 1);
if (count == 0)
{
strcpy(new_array[0].name, test_Country_obj.name);
}
else
{
for (int i = 0; i < count; i++)
{
if (strcasecmp(new_array[i].name, test_Country_obj.name) == 0)
{
printf("%s", "test_Country already added\n");
flag = 1;
break;
}
}
}
if (flag == 0)
{
strcpy(new_array[count].name, test_Country_obj.name);
test_Country_obj.gold = 0;
test_Country_obj.silver = 0;
test_Country_obj.bronze = 0;
new_array[count] = test_Country_obj;
count = count + 1;
}
flag = 0;
return new_array;
}
int main()
{
char choice;
test_Country *array = malloc(sizeof(test_Country));
test_Country test_Country_obj;
printf("%s", "Enter your choice : ");
scanf("%s", &choice);
//fgets(ptr, 80, stdin);
//sscanf(ptr, "%c %s %d %d %d", &choice, test_Country_obj.name, &test_Country_obj.gold, &test_Country_obj.silver, &test_Country_obj.bronze);
//printf("%s", &choice);
while (choice != 'E')
{
printf("%s", "Enter test_Country name : ");
scanf("%s", test_Country_obj.name);
array = addtest_Country(test_Country_obj, array);
//printf("%d%s", count, "is count");
printf("%s", "Enter your choice : ");
scanf("%s", &choice);
}
}
I cant seem to understand what is wrong.
char choice;
scanf("%s", &choice);
is bad. choice has only room for one character, so it can hold only strings upto zero characters. (the one-character room is for terminating null-character). Trying to store strings longer than zero character leads to dangerous out-of-range write and it may destroy data around that.
To avoid out-of-range write, you should allocate enough elements and specify the maximum length to read. The maximum length should be the buffer size minus one for terminating null-character.
char choice[16]; /* allocate enough elements */
scanf("%15s", choice); /* specify the maximum length */
After that, choice in the while and switch should be replaced with choice[0] to judge by the first character. Another way is using strcmp() to check the whole string.

How to count characters in a string after splitting the word?

I found this c programming code on https://www.includehelp.com/c-programs/c-program-to-split-string-by-space-into-words.aspx
/*C program to split string by space into words.*/
#include <stdio.h>
#include <string.h>
int main()
{
char str[100];
char splitStrings[10][10]; //can store 10 words of 10 characters
int i,j,cnt;
printf("Enter a string: ");
gets(str);
j=0; cnt=0;
for(i=0;i<=(strlen(str));i++)
{
// if space or NULL found, assign NULL into splitStrings[cnt]
if(str[i]==' '||str[i]=='\0')
{
splitStrings[cnt][j]='\0';
cnt++; //for next word
j=0; //for next word, init index to 0
}
else
{
splitStrings[cnt][j]=str[i];
j++;
}
}
printf("\nOriginal String is: %s",str);
printf("\nStrings (words) after split by space:\n");
for(i=0;i < cnt;i++)
printf("%s\n",splitStrings[i]);
return 0;
}
I had run this code and I have entered the string for an example "The dog is sad" The output will be
The
Dog
Is
Sad
I was wondering if I could count the numbers of the characters after splitting the word; like for an example;
The 3
Dog 3
Is 3
Sad 3
I do not know how to achieve that desired output. Thank you
Your last printf could be:
printf("%s %d ",splitStrings[i], strlen(splitStrings[i]));
You already use strlen() in your first for loop.
Use this modified printf:
/*C program to split string by space into words.*/
#include <stdio.h>
#include <string.h>
int main()
{
char str[100];
char splitStrings[10][10]; //can store 10 words of 10 characters
int i,j,cnt;
printf("Enter a string: ");
gets(str);
j=0; cnt=0;
for(i=0;i<=(strlen(str));i++)
{
// if space or NULL found, assign NULL into splitStrings[cnt]
if(str[i]==' '||str[i]=='\0')
{
splitStrings[cnt][j]='\0';
cnt++; //for next word
j=0; //for next word, init index to 0
}
else
{
splitStrings[cnt][j]=str[i];
j++;
}
}
printf("\nOriginal String is: %s",str);
printf("\nStrings (words) after split by space:\n");
for(i=0;i < cnt;i++)
printf("%s %d ",splitStrings[i],strlen(splitStrings[i]));//modified
return 0;
}

strings to arrays then print in c

I am trying to take a user inputted string and look at each code to see if it appears in another string of strings. So far my code works.
If the word is successfully found then the alpha representation is to be added to an array that will eventually be printed, but only if all codes were found.
I am having issues with what gets stored in my array that is going to be printed.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef char *string;
typedef char *alpha;
int main(void)
{
string morse[4]={".-", "-...","----.", ".."};
string alpha[4]={"A", "B", "9", "I"};
char prntArr[50];
char *input;
char *hold;
input = malloc(200);
hold = malloc(50);
int i=0;
int j=0;
int ret;
int x;
int w=0;
int z=0;
printf("please enter a string\n");
scanf("%[^\n]",input);
do{
if (input[i] !=' ')
{
hold[j] = input[i];
j++;
}
else
{
hold[j]='\0';
for (x=0;x<4;x++)
{
printf("value of x %d\n",x);
ret = strcmp(morse[x], hold);
if (ret==0)
{
printf("%s\n",alpha[x]);
prntArr[w]=*hold;
w++;
x=4;
}
else
{
ret=1;
printf("invalid Morse code!");
}
}
j = 0;
}
i++;
}while(input[i] !='\0');
for (z=0;z<50;z++)
{
printf("%c",prntArr[z]);
}
return 0;
free(input);
}
The problem you asked about is caused by the way prntArr is used in the program. It really should be an array of character pointers into the alpha array. Instead, it's manipulated as an array of characters into which the first character of each morse code element is stored. And when it's printed, the variable that tracks how much of the array is used is simply ignored.
Another problem is that your code uses spaces to break the codes but there won't necessarily be a space at the end of the line so a code might get missed. In the program below, I switched out scanf() for fgets() which leaves a newline character on the end of the input which we can use, like space, to indicate the end of a code.
Other problems: you print the invalid Morse code message at the wrong point in the code and you print it to stdout instead of stderr; you remember to free input but forget to free hold; you put code after return that never gets called.
Below is a rework of your code that addresses the above problems along with some style issues:
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
int main(void)
{
char *morse[] = {".-", "-...", "----.", ".."};
char *alpha[] = {"A" , "B" , "9" , "I" };
char *print_array[50];
int print_array_index = 0;
char hold[50];
int hold_index = 0;
char input[200];
int i = 0;
printf("please enter a string: ");
fgets(input, sizeof(input), stdin);
while (input[i] !='\0') {
if (input[i] ==' ' || input[i] == '\n')
{
hold[hold_index] = '\0';
bool found = false;
for (int x = 0; x < sizeof(morse) / sizeof(char *); x++)
{
if (strcmp(morse[x], hold) == 0)
{
print_array[print_array_index++] = alpha[x];
found = true;
break;
}
}
if (!found)
{
fprintf(stderr, "invalid Morse code: %s\n", hold);
}
hold_index = 0;
}
else
{
hold[hold_index++] = input[i];
}
i++;
}
for (int x = 0; x < print_array_index; x++)
{
printf("%s ", print_array[x]);
}
printf("\n");
return 0;
}
SAMPLE RUNS
> ./a.out
please enter a string: ----. -... .- ..
9 B A I
>
> ./a.out
please enter a string: .- --- ..
invalid Morse code: ---
A I
>

How to find the length of an input

i am trying to measure how many numbers my input has.
if i input the following line: 1 2 65 3 4 7,
i want the output to be 8.but what I'm getting is 1 2 3 4.
#include <stdio.h>
int main(void) {
int data;
int i = 1;
while (i <= sizeof(data)) {
scanf("%d", &data)
printf("%d", i);
i++;
}
}
You are printing i which have no relation to the input at all. So no matter what your input is, you'll get 1234
sizeof(data) is the same as sizeof(int), i.e. a constant with value 4 on your system.
If you want to count the number of numbers and don't care about the value of the individual number, you could do:
#include <stdio.h>
#include <ctype.h>
int main(void) {
char s[1024];
char* p;
int i = 0;
fgets(s, 1024, stdin);
p=s;
while (*p != '\0')
{
if (!isdigit(*p))
{
p++;
}
else
{
i++; // Found new number
// Search for a delimiter, i.e. skip all digits
p++;
while (*p != '\0' && isdigit(*p))
{
p++;
}
}
}
printf("We found %d numbers", i);
return 0;
}
Output:
We found 6 numbers
Notice that this code will accept any non-digit input as delimiter.
put the scanf before the while-loop and move the printf after the while-loop.
I'm also providing solution according to my openion.
#include <stdio.h>
int main(void) {
int data = 1;
int i = 0;
// here data != 0 is trigger point for end input,
// once you done with your inputs you need to last add 0 to terminate
while (data != 0) {
scanf("%d", &data)
printf("Collected Data: %d", data);
i++;
}
printf("Total number of inputs are %d.", i);
}
Hope this solution helps you.
Here is my solution:
#include <stdio.h>
#include <stdlib.h>
int main() {
int i = 0;
int data[100]; // creating an array
while(1) { // the loop will run forever
scanf("%d", &data[i]);
if (data[i] == -1) { //unless data[i] = -1
break; // exit while-loop
}
i++;
}
printf("%d\n", data[2]); // print 2nd integer in data[]
return 0;
}
Do not forget to hit enter once you entered an int. Output of the program:
2
56
894
34
6
12
-1
894
Hope that helps. :)

Resources