Program in c crashes - c

My code seems to crash everytime i run it, i want to make a program that finds a capital letter in a sentence (str[max]) and it prints out how many times it finds it
i get a warning from the build log (warning: 'c' may be used uninitialized in this function) (very entry level programmer here !!)
#include <stdio.h>
#include <string.h>
#include "genlib.h"
#include "simpio.h"
#include "ctype.h"
#define max 26
void checktimes(char str[],char temp);
int main()
{
char str[max], temp;
printf("Type a sentence with 25 characters max :");
gets(str);
int i;
for(i=0;i<=max;i++)
{
temp = str[i];
if(isupper(temp))
checktimes(str,temp);
}
return 0;
}
void checktimes(char str[],char temp)
{
int j,i;
char c;
for(j=0; j<=max ; j++)
{
str[i] = c;
if(c == temp)
i++;
}
printf("%c --> %d",temp,i);
}

You have multiple problems:
1) Never use gets(). Use fgets() instead.
2) You may not always have max number of characters. So, your condition: for(i=0;i<=max;i++) is probably wrong.
Use strlen() to find out the actual number of chars in str.
3) You are reading c uninitialized here:
str[i] = c;
You probably meant:
c = str[j]; /* notice the i -> j change */
4) The argument to isupper() requires a cast to unsigned char.
5) Initialize i to 0 in checktimes().
In fact, there's a logical error as well. You would be printing the count of duplicate chars as many times.
If you use an temp array, it can be written as:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define max 26
void checktimes(char str[]);
int main(void)
{
char str[max];
printf("Type a sentence with 25 characters max :");
fgets(str, sizeof str, stdin);
str[strcspn(str, "\n")] = 0; /* To remove the trailing newline if any. */
checktimes(str);
return 0;
}
void checktimes(char str[])
{
int i = 0;
int count[max] = {0};
size_t len = strlen(str);
for(i=0; i<len; i++)
{
if(isupper((unsigned char)str[i]))
count[str[i] - 'A']++;
}
for(i = 0; i < max; i++)
if (count[i])
printf("%c --> %d\n",i+'A', count[i]);
}

Related

scanf does not work with &str when str is defined as char str[100]

Please, can someone tell me what is the problem in my syntax. I want to find the duplicate letters in a word. it is working properly if I declare a character array here itself but not working with scanf.
#include<stdio.h>
// Finding the duplicate alphabets in a string
int length(char str[]) //Finding the length of the string
{
int len;
while(str[len]!='\0')
{
len++;
}
return len;
}
void duplicate(char str[],int n)
{
int i,j,flag;
for(i=0;i<=n-2;i++) //Selecting the alphabet for comparison
{
flag=0;
if(str[i]!='\0')
{
for(j=i+1;j<=n-1;j++) //comparison of alphabets
{
if(str[j]==str[i])
{
flag=1;
str[j]=0;
}
}
if(flag==1)
{
printf("%c is the duplicate character\n",str[i]);
}
}
}
}
int main()
{
char str[100];
scanf("%s",&str);
int n= length(str);
duplicate(str,n);
}
The problems that I noticed:
main: scanf("%s",&str); is the wrong type for str (char (*)[100]) and should be scanf("%s", str);. char str[100] uses a magic 100 value, instead #define STR_LEN 99 so you can do char str[STR_LEN + 1]. The way you use scanf is subject to buffer overflow instead you should use scanf("%" str(STR_LEN) "s", STR_LEN, str) and you need #define str(s) xstr(s) and #define xstr(s) #s. I suggest using fgets instead.
length: int len; is uninitialized and should be int len = 0; (len is not a great variable name as it's usually 1 bigger than last index, but you use it to index with). Why did you write your own instead of using strlen? As you only return values 0 or great, consider using unsigned instead of int for the type of i and the return value.
duplicate (minor issue): it's good practice to minimize variable scope so for(int i = 0; ... and declare flags where you initilize it. You should technically ensure that n > INT_MIN + 1 for underflow, or change type to an unsigned value, or just calculate it yourself internally.
You can also create an array of counts for each letter. Initialized to 0, and add 1 as you find each letter. Then report the letters with count > 1. This would be a O(n) algorithm instead of the original O(n^2).
#include <limits.h>
#define CHARS (UCHAR_MAX+1)
void duplicate(char *str) {
unsigned char counts[CHARS] = { 0 }; // 0, 1 or 2 for 2+
for(unsigned i=0; str[i]; i++) {
char *c = counts + (unsigned) str[i];
*c += *c <= 1;
}
for(unsigned i=0; i<CHARS; i++) {
if(counts[i] > 1) {
printf("%c is the duplicate character\n", (char) i);
}
}
}
As advised, always ensure that your local variables are initialized before attempting to use them. As for your problem, if your sole desire is to find duplicate strings then you could approach it this way:-
#include<stdio.h>
#define CHAR_SIZE 100
int length(char[]);
void duplicate(char[], int);
// Finding the duplicate alphabets in a string
int length(char str[]) //Finding the length of the string
{
int len = 0;
while(str[len] !='\0')
len++;
return len;
}
//find duplicates
void duplicate(char str[],int n)
{
for(int i =0; i < n; i++)
for(int j=i+1; j<n; j++)
if(str[i] == str[j])
printf("%c is the duplicate character\n",str[i]);
}
//test case
int main()
{
char str[CHAR_SIZE];
puts("Enter string\n");
scanf("%s",str);
int n= length(str);
printf("len of entered str is %d\n\n", n);
duplicate(str,n);
}

How do I check if this is spelled correct letter by letter?

In this code you "randomly" fill your array with letters and if it hits the word you are looking for returns the amount of trys to get it correct. What I want to implement is a way of checking if it is spelled correct from the first character going onwards. Any ideas?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
int main() {
char *search= "SOMETHING";
int clk = clock();
printf ("clk=%d\n",clk);
srand(clk);
int len = strlen(search);
char *tafel = (char *) malloc (len+1);
tafel[len] = 0;
int pos;
char letter;
long i=0;
char check;
while (strcmp (search,tafel) != 0 ) {
i++;
letter = rand() % 26 +'A';
pos = rand() % len;
//pos=(pos+1)%len;
tafel[pos] = letter;
if (i%10000000==0) {
printf("%4ld mio: %s\n", i / 1000000, tafel);
printf ("%d\n",strcmp (search,tafel));
}
}
printf("It takes %ld trys to find '%s'\n",i,tafel);
printf ("%d\n",strcmp (suchwort,tafel));
return 0;
}

copying int to a string

I'am trying to learn c and therefore solving this exercise. My problem is in the part where I have to abbreviate a word. I am using sprintf to convert the integer to a string and write it into my old string. But however I try to achieve it, the last character of the string always gets lost. Why does this happen? Here is the code:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
void abreviation(char *arr,int length){
if ( length+1 > 10){
char c = arr[length];
sprintf(arr+1, "%d%c", length-1,c);
}
}
int main() {
int n,i,j;
scanf("%d\n",&n);
char **arr = malloc(n*sizeof(char*));
for(i=0; i < n ; i++){
arr[i] = malloc(sizeof(char)*100);
char c;
for ( j=0; (c = getchar()) != '\n' ; j++)
arr[i][j]=c;
arr[i][j+1]='\0';
abreviation(arr[i],j);
}
for(i=0; i < n; i++)
printf("%s\n", arr[i]);
}
I appreciate any help.
The loop you wrote to input the words stop at '\0', at that point j is indexed to '\0', and then in the abreviation function char c = arr[length c will always be \0 and not the last char in the word (arr).
A simple fix is to change
abreviation(arr[i],j);
to
abreviation(arr[i],j-1);

Program prints unrelated chars

I wanted to split an array to 2 arrays that the first one contains the lowercased letters of the original array and the second one contains the uppercased letters and from some reason it prints some unrelated chars.
#include <stdio.h>
#include <string.h>
#define LEN 8
int main(void)
{
char str[] = "SHaddOW";
char smallStr[LEN], bigStr[LEN];
int i = 0;
int indexSmall = 0;
int indexBig = 0;
for (i = 0; i <= LEN; i++)
{
if (str[i] <= 'Z')
{
smallStr[indexSmall] = str[i];
indexSmall++;
}
if (str[i] >= 'Z')
{
bigStr[indexBig] = str[i];
indexBig++;
}
}
printf("1: ");
puts(smallStr);
printf("2: ");
puts(bigStr);
system("PAUSE");
return 0;
}
Don't define length before you create the string to test.
Create it's length after defining the string to test.
Copy the characters as you encounter them, but as #Ed Heal says you must add a null terminator so that you can print out the two strings (they aren't really strings until they are null terminated).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main (void)
{
char str[] = "SHaddOW";
int len = strlen(str) +1;
char smallStr[len], bigStr[len];
char term[] = {'\0'};
int n, s, b;
s=0;
b=0;
for(n=0; n<len; n++) {
if(islower(str[n])) {
memcpy(smallStr +s, str +n, 1);
s++;
} else if (isupper(str[n])){
memcpy(bigStr +b, str +n, 1);
b++;
}
}
memcpy(smallStr + s, term, 1);
memcpy(bigStr + b , term, 1 );
printf("Upper: %s\n", bigStr);
printf("Lower: %s\n", smallStr);
}
Output:
Upper: SHOW
Lower: add
Add this to the if structure (and other code to support it)
} else {
memcpy(anyStr +a, str +n, 1);
a++;
}
then:
char str[] = ".S1H2a3d4d5O6W.";
and:
printf("Anything else: %s\n", anyStr);
returns:
Upper: SHOW
Lower: add
Anything else: .123456.
A more compact approach with (perhaps) more meaningful variable names:
#include <stdio.h>
#include <ctype.h>
#include <stdint.h>
#include <string.h>
int main ( void ) {
const char str[] = "SHaddOW";
size_t len = strlen(str); /* better to get actual length */
char lowers[len + 1]; /* add one for the nul char */
char uppers[len + 1]; /* (see below) */
int c;
int i = 0;
int n_upper = 0;
int n_lower = 0;
while ((c = str[i++]) != '\0') {
if (isupper(c)) uppers[n_upper++] = c; /* no need to reinvent */
if (islower(c)) lowers[n_lower++] = c; /* the wheel here */
}
uppers[n_upper] = '\0'; /* the nul char ('\0') marks */
lowers[n_lower] = '\0'; /* the end of a C "string" */
printf("1: %s\n", lowers);
printf("2: %s\n", uppers);
return 0;
}
Notes
If you are super concerned about efficiency you could add an else before if (islower...
Adding const means you "promise" the characters in the array won't be changed.
The type size_t is an integer type, but may be larger than int. It is the correct type for the return of strlen(). It is defined in <stdint.h>. None the less, using int will almost always work (on most systems a string would have to be 'yooooge' for its length to be bigger than an int can hold).
The variable c is declared as int instead of char because int is the proper type for the isXXXXX() functions (which are defined in <ctype.h>). It is also a good habit to get into because of the parallels between this loop and another common idiom while ((c = fgetc(fp)) != EOF) ....
You should consider using isupper() and islower() functions. Code would be cleaner. And what if you have some non alpha characters? Your conditions won't work.
for (i = 0; i < LEN; i++)
{
if (islower(str[i]))
{
smallStr[indexSmall] = str[i];
indexSmall++;
}
else if (isupper(str[i]))
{
bigStr[indexBig] = str[i];
indexBig++;
}
}
As #Ed Heal mention. To avoid printing rubbish, after for loopt you should add a null characters to arrays.
smallStr[indexSmall] = '\0';
bigStr[indexBig] = '\0';

Palindrome Program

I've created a program that takes an inputted string and outputs the string backwards. I've created a function that counts the number of characters in a string. With that information, I've created another function that puts the first character of the original array at the end of the new array. Thus, when the loop in the function has finished, the new array contains the letters of the original array but backwards. I'm running into some difficulty however. I'm still wary of character arrays and I'm not sure if I'm using them correctly. Could someone help me out?
#include <stdio.h>
#define MAXLINE 1000
char backward(char str[], int count)
int count(char str[])
int main() {
char orig[MAXLINE];
int c;
scanf("%s", orig);
c = count(orig);
printf("%s", backward(orig, c));
return 0;
}
char backward(char str[], int count) {
char back[MAXLINE];
int i;
for(i = 0; i <= count; ++i) {
back[count] = str[i];
--count;
return back;
}
int count(char str[]) {
int i;
for (i = 0; str[i] != '\0'; ++i)
;
return i;
}
Edit: Input: Let's say "minivan". Expected output would be "navinim". There's no actual output yet. I'm getting this error:
palindrome.c:8: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘int’
The error you're getting is because your prototypes are wrong:
#include <stdio.h>
#define MAXLINE 1000
char backward(char str[], int count) /* missing ; */
int count(char str[]) /* missing ; */
int main() {
You should also consider replacing count() with strlen(3) from the <string.h> header file. The standard library is full of utilities that have been debugged and known to work well -- it is worth using them. (Yes, there's educational value in re-implementing them. But in that case, be prepared to test with a variety of corner cases.)
Your code probably won't compile because you missed a closing brace in backward().
char backward(char str[], int count) {
char back[MAXLINE];
int i;
for(i = 0; i <= count; ++i) {
back[count] = str[i];
--count;
/** You should add a } character here! **/
return back;
}
MAJOR EDIT 1:
I tried to compile your code and there were lots of things wrong with it. Here is working code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXLINE 1000
char * backward(char * str);
int main() {
char orig[MAXLINE];
int c;
scanf("%s", orig);
printf("%s\n", backward(orig));
return 0;
}
char * backward(char * str) {
int count = strlen(str);
char * back = malloc(MAXLINE);
int i;
for(i = 0; i < count; i++)
{
back[count-i-1] = str[i];
}
back[count] = 0; // Add the null termination character.
return back;
}
When I run this code and enter "abcde", it outputs "edcba". Let me know if you have any specific questions about how this works. I got rid of your count() function because it is a duplicate of strlen(), and I moved the call to strlen() inside the backward() to make the interface to the backward() function simpler.
Another thing that made your code fail is that you were decrementing count inside the for loop, which would cause your for loop to terminate earlier than you wanted it to.
This line has an off by one mistake:
back[count] = str[i];
count is not the last character of the string, it's the '\0' character.
Also you are returning a stack variable - this is not going to work.
You should reverse the string in place:
for(i = 0; i <= count; ++i) {
--count;
char tmp = str[i];
str[i] = str[count];
str[count] = tmp;
}
You can then return str.
You program have lot of errors. Firstly you have missed out semicolons(;) while declaring the prototypes for backward and count. Then you haven't closed the for loop in backward function with ending braces(}).
But the biggest three problems are
1. You have defined backward function as a char data type but you are returning a pointer to the array of char data type
2. You are accessing back[count] instead of back[count-1]. Suppose the string is minivan. The count will hold 7. the last character is at 6th position not 7th because in array subscripts starts with 0 not 1. And back[count] will point to null character i.e '\0'
3. You are incrementing i and decrementing count and checking i<=count. This will process your string only till mid of it.
Although the right program has been posted by David Greyson, but since he have removed the count function and introduced the strlen and malloc function, I am posting your program again by just correcting your algorithm
#include <stdio.h>
#define MAXLINE 1000
char *backward(char str[], int count);
int count(char str[]);
int main() {
char orig[MAXLINE];
int c;
scanf("%s", orig);
c = count(orig);
printf("%s", backward(orig, c));
return 0;
}
char *backward(char str[], int count) {
char back[MAXLINE];
int i;
for(i = 0; i < count; ++i) {
back[count-i-1] = str[i];
}
back[i] = '\0';
return back;
}
int count(char str[]) {
int i;
for (i = 0; str[i] != '\0'; ++i)
;
return i;
}
You can create a character pointer then add length of string to this pointer, it should likely char *reverse = (char *)name, then add reverse = reverse + strlen(name) -1.
Then you can use while loop through through the start of string. The whole code looks,
void main(void)
{
char *name = "Kernel";
char *reverse = (char *)name;
reverse = reverse + strlen(name) - 1;
while(*reverse)
printf("%c", *reverse);
}
#include<Stdio.h>
#include<string.h>
int main()
{
size_t i,j;
char arr[10]={'\0'};//orignal array
char arr2[10]={'\0'};//it's reverse to be
gets(arr);//prompt
strncpy(arr2,arr,10);//copy
strrev(arr2);
if(strncmp(arr,arr2)==0)
printf("plaindrom");
return 0;
}

Resources