wrong output from strcpy function in for loop - arrays

#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main() {
char questions[][100] = {"1. what year did the c language debut?:",
"2. who is credited with crating c?:",
"3. what is the predecossor of c?:"};
char options[][100] = {"a. 1969","b. 1972","c. 1975","d. 1999",
"a. dennis r.","b. nikola tesla","c. john carmarck","d. doc b.",
"a. objective c","b. b","c. c++","d. c#"};
char answers[3] = {'b','a','b'};
int numberofquestions = sizeof(questions) / sizeof(questions[0]);
char space[] = " ";
char guess[numberofquestions];
char results[3][7];
int score = 0;
for(int i = 0; i < numberofquestions * 4; i++){
strncat(options[i], space, 25 - strlen(options[i]));
}
for(int i = 0; i < numberofquestions; i++){
printf("\n%s\n", questions[i]);
for(int j = 4 * i; j < 4 * (i + 1); j++){
printf("%s", options[j]);
}
printf("\n\nguess: ");
scanf("%c", &guess[i]);
scanf("%*c"); // this is for clearing \n from input buffer, * for ??
if(guess[i] == answers[i]){
score++;
}
}
for(int i = 0; i < numberofquestions; i++){
if(guess[i] == answers[i]){
strcpy(results[i], "correct");
}
else{
strcpy(results[i], "wrong");
}
}
printf("\n1st question is %s\n", results[0]);
printf("2nd question is %s\n", results[1]);
printf("3rd question is %s\n", results[2]);
printf("\ntotal score is %d/%d", score, numberofquestions);
return 0;
}
W
hen I run the code with the correct answers 'b', 'a', and 'b' i get the output
1st question is correctcorrectcorrect
2nd question is correctcorrect
3rd question is correct
total score is 3/3
but if I run with the wrong answers I get the output
1st question is wrong
2nd question is wrong
3rd question is wrong
total score is 0/3
How can I fix this ?

The short answer is that your results buffer char results[3][7] isn't big enough.
C strings are NULL terminated which means that each string literal needs an extra char to mark the end.
So, the literal "wrong" actually has length 6, and "correct" has length 8.
The entries in results are arranged consecutively in memory, so when you copy "correct" into results[i] the null terminating character spills into the space for results[i+1][0]. When results[i+1] is copied into place it overwrites that character.
You can fix this here by increasing the size of the buffers: char results[3][8].

Related

resolving memory loss between two arrays in C

Good evening. I'm working on a program for class and I am hitting a brick wall when it comes to dealing with arrays using C.
--EDIT-- Full code has been posted.
#define _CRT_SECURE_NO_WARNINGS
#define STRMAX 20
#define MAX 100
#include<stdio.h>
int main()
{
int count = 0;
char strlist[STRMAX][MAX];
int start = 0, end = STRMAX;
for (start; start < end; start++) {
char string[MAX];
printf("Enter a string: ");
fgets(string, MAX - 1, stdin);
printf("\nThe string is: %s", string);
int size = strlen(string);
int result = strcmp(string, "stop\n");
if (result == 0) {
break;
}
strcpy(strlist[start], string);
count = count + 1;
}
char rev[STRMAX][MAX];
int temp = 0;
printf("count is: %d\n",count);
while (count != 0) {
strcpy(rev[temp], strlist[count]);
temp = temp + 1;
count = count - 1;
}
printf(rev);
return 0;
}
The last line, printf(rev); is throwing the warning: "using uninitialized memory 'rev'. "
I do not understand C, its the beginning of this course. However I am NOT looking for a "do my homework for me" answer, more of a "here is a better way to go about this" answer.
the output for the code is:
Enter a string: 1
The string is: 1
Enter a string: 2
The string is: 2
Enter a string: 3
The string is: 3
Enter a string: stop
The string is: stop
count is: 3
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠3
the "count is: 3" is entirely for debugging. I really don't have a clue why my solution doesn't work. If there is any more information that is needed or anything else you would like to see feel free to ask and i'll update the post! thanks.
--EDIT--
STRMAX and MAX are both definitions set for the 2D array required for keeping an array of strings (20 and 50 respectively)
First of all, the line
strcpy(rev[temp], strlist[count]);
is wrong. Valid indexes for strlist are 0 to count-1, assuming that you only want to read valid strings. However, you are using the indexes 1 to count instead. Therefore, you should move the line
count = count - 1;
before that line.
Also, the line
printf(rev);
does not make sense.
If you want to print all strings in the array, then you should print every string individually, in a loop.
Since you are storing the number of valid strings in the variable temp, you must print that many strings.
for ( int i = 0; i < temp; i++ )
{
printf( "%s\n", rev[i] );
}
Also, you should #include <string.h>, because you are using strcpy and strlen.
Additionally, you probably should remove the trailing newline character from the input obtained from fgets. Otherwise, you will be printing that newline character, which will give you unwanted extra lines, forcing you to compensate by printing less newline characters explicitly. The existance of the newline character is also forcing you to add a newline character to the target string "stop":
int result = strcmp(string, "stop\n");
You will be able to remove that newline character from the target string if you also remove it from the input string.
After making these changes, your code should look like this:
#define _CRT_SECURE_NO_WARNINGS
#define STRMAX 20
#define MAX 100
#include <stdio.h>
#include <string.h>
int main()
{
int count = 0;
char strlist[STRMAX][MAX];
int start = 0, end = STRMAX;
for (; start < end; start++) {
char string[MAX];
printf("Enter a string: ");
fgets(string, MAX - 1, stdin);
//remove trailing newline character
string[strcspn(string,"\n")] = '\0';
printf("The string is: %s\n", string);
int result = strcmp(string, "stop");
if (result == 0) {
break;
}
strcpy(strlist[start], string);
count = count + 1;
}
char rev[STRMAX][MAX];
int temp = 0;
printf("count is: %d\n",count);
while (count != 0) {
count = count - 1;
strcpy(rev[temp], strlist[count]);
temp = temp + 1;
}
for ( int i = 0; i < temp; i++ )
{
printf( "%s\n", rev[i] );
}
return 0;
}
This program has the following output:
Enter a string: 1
The string is: 1
Enter a string: 2
The string is: 2
Enter a string: 3
The string is: 3
Enter a string: stop
The string is: stop
count is: 3
3
2
1

A program that prints even and odd characters from a string

This is for Homework
I have to write a program that asks the user to enter a string, then my program would separate the even and odd values from the entered string. Here is my program.
#include <stdio.h>
#include <string.h>
int main(void) {
char *str[41];
char odd[21];
char even[21];
int i = 0;
int j = 0;
int k = 0;
printf("Enter a string (40 characters maximum): ");
scanf("%s", &str);
while (&str[i] < 41) {
if (i % 2 == 0) {
odd[j++] = *str[i];
} else {
even[k++] = *str[i];
}
i++;
}
printf("The even string is:%s\n ", even);
printf("The odd string is:%s\n ", odd);
return 0;
}
When I try and compile my program I get two warnings:
For my scanf I get "format '%s' expects arguments of type char but argument has 'char * (*)[41]". I'm not sure what this means but I assume it's because of the array initialization.
On the while loop it gives me the warning that says comparison between pointer and integer. I'm not sure what that means either and I thought it was legal in C to make that comparison.
When I compile the program, I get random characters for both the even and odd string.
Any help would be appreciated!
this declaration is wrong:
char *str[41];
you're declaring 41 uninitialized strings. You want:
char str[41];
then, scanf("%40s" , str);, no & and limit the input size (safety)
then the loop (where your while (str[i]<41) is wrong, it probably ends at once since letters start at 65 (ascii code for "A"). You wanted to test i against 41 but test str[i] against \0 instead, else you get all the garbage after nul-termination char in one of odd or even strings if the string is not exactly 40 bytes long)
while (str[i]) {
if (i % 2 == 0) {
odd[j++] = str[i];
} else {
even[k++] = str[i];
}
i++;
}
if you want to use a pointer (assignement requirement), just define str as before:
char str[41];
scan the input value on it as indicated above, then point on it:
char *p = str;
And now that you defined a pointer on a buffer, if you're required to use deference instead of index access you can do:
while (*p) { // test end of string termination
if (i % 2 == 0) { // if ((p-str) % 2 == 0) { would allow to get rid of i
odd[j++] = *p;
} else {
even[k++] = *p;
}
p++;
i++;
}
(we have to increase i for the even/odd test, or we would have to test p-str evenness)
aaaand last classical mistake (thanks to last-minute comments), even & odd aren't null terminated so the risk of getting garbage at the end when printing them, you need:
even[k] = odd[j] = '\0';
(as another answer states, check the concept of even & odd, the expected result may be the other way round)
There are multiple problems in your code:
You define an array of pointers char *str[41], not an array of char.
You should pass the array to scanf instead of its address: When passed to a function, an array decays into a pointer to its first element.
You should limit the number of characters read by scanf.
You should iterate until the end of the string, not on all elements of the array, especially with (&str[i] < 41) that compares the address of the ith element with the value 41, which is meaningless. The end of the string is the null terminator which can be tested with (str[i] != '\0').
You should read the characters from str with str[i].
You should null terminate the even and odd arrays.
Here is a modified version:
#include <stdio.h>
int main(void) {
char str[41];
char odd[21];
char even[21];
int i = 0;
int j = 0;
int k = 0;
printf("Enter a string (40 characters maximum): ");
if (scanf("%40s", str) != 1)
return 1;
while (str[i] != '\0') {
if (i % 2 == 0) {
odd[j++] = str[i];
} else {
even[k++] = str[i];
}
i++;
}
odd[j] = even[k] = '\0';
printf("The even string is: %s\n", even);
printf("The odd string is: %s\n", odd);
return 0;
}
Note that your interpretation of even and odd characters assumes 1-based offsets, ie: the first character is an odd character. This is not consistent with the C approach where an even characters would be interpreted as having en even offset from the beginning of the string, starting at 0.
Many answers all ready point out the original code`s problems.
Below are some ideas to reduce memory usage as the 2 arrays odd[], even[] are not needed.
As the "even" characters are seen, print them out.
As the "odd" characters are seen, move them to the first part of the array.
Alternative print: If code used "%.*s", the array does not need a null character termination.
#include <stdio.h>
#include <string.h>
int main(void) {
char str[41];
printf("Enter a string (40 characters maximum): ");
fflush(stdout);
if (scanf("%40s", str) == 1) {
int i;
printf("The even string is:");
for (i = 0; str[i]; i++) {
if (i % 2 == 0) {
str[i / 2] = str[i]; // copy character to an earlier part of `str[]`
} else {
putchar(str[i]);
}
}
printf("\n");
printf("The odd string is:%.*s\n ", (i + 1) / 2, str);
}
return 0;
}
or simply
printf("The even string is:");
for (int i = 0; str[i]; i++) {
if (i % 2 != 0) {
putchar(str[i]);
}
}
printf("\n");
printf("The odd string is:");
for (int i = 0; str[i]; i++) {
if (i % 2 == 0) {
putchar(str[i]);
}
}
printf("\n");
here is your solution :)
#include <stdio.h>
#include <string.h>
int main(void)
{
char str[41];
char odd[21];
char even[21];
int i = 0;
int j = 0;
int k = 0;
printf("Enter a string (40 characters maximum): ");
scanf("%s" , str);
while (i < strlen(str))
{
if (i % 2 == 0) {
odd[j++] = str[i];
} else {
even[k++] = str[i];
}
i++;
}
odd[j] = '\0';
even[k] = '\0';
printf("The even string is:%s\n " , even);
printf("The odd string is:%s\n " , odd);
return 0;
}
solved the mistake in the declaration, the scanning string value, condition of the while loop and assignment of element of array. :)

How to calculate frequency of characters in a string [duplicate]

This question already has an answer here:
C program: how to find the maximum/minimum frequency of a character in a string
(1 answer)
Closed 6 years ago.
I am a beginner with C programming so my code is very basic. It is to count the frequency of characters in a string. The program does run but the problem is that it displays each character as many times as it appears in the string. So, when I enter hello, I get "h occurs 1 times, e occurs 1 times, l occurs 2 times, l occurs 2 times, o occurs 1 times". How do i eliminate this and make the count for l appear only once?
for(i=0;str[i]!='\0';i++)
{
for(j=0;str[j]!='\0';j++)
{
if(str[i]==str[j])
count[i]++;
}
}
for(i=0;i<str[i]!='\0';i++)
printf("%c occurs %d times \n",str[i],count[i]);
I think building your own function which removes duplicated characters would help you in achieving what you are trying to do. But, there is no standard function that would help you in removing all the duplicates from a string. So try constructing a function to remove all the duplicated/repeated characters from a string and returns the string. Here's what your function would look like:
char* remove_duplicated(char* str, int size) {
int frequency[256] = {0};
char* new_str = malloc(size);
int new_size = 0;
for(int i=0; str[i]!='\0'; i++)
{
if(frequency[(unsigned char) str[i]] == 0) {
frequency[(unsigned char) str[i]]++;
new_str[new_size] = str[i];
new_size++;
}
}
new_str[new_size] = '\0';
return new_str;
}
Once you have constructed the above function, send the string in which you want to have the frequencies of characters measured and store the returned string. Something like this:
char* new_str = remove_duplicated(str, size);
Now in the double for loop that you are using, use new_str for your outer for loop and also use it for the for loop displaying count
for(i=0; new_str[i]!='\0'; i++)
{
for(j=0; str[j]!='\0'; j++)
{
if(new_str[i] == str[j])
count[i]++;
}
}
for(i=0; new_str[i]!='\0'; i++)
printf("%c occurs %d times \n", new_str[i], count[i]);
don't forget to free the malloced array in the remove_duplicated function:
free(new_str);
Here's an online demo: https://ideone.com/KnkwGX
You can use something like
int characters[128] = {0};
char string[] = "Hello, World!";
for(int i = 0; string[i] != '\0'; i++)
characters[(int)string[i]]++;
for(int i = 0; i < 128; i++)
if(characters[i] != 0)
printf("%c occurs %d times\n", (char)i, characters[i]);
It is going to be a little difficult to print the count of each letter uniquely with the way you have coded. Try the following way:
int frequency[122] = {0}; //ascii value of z is 122.
for(i=0;str[i]!='\0';i++)
{
frequency[str[i]]++;
}
for(i=0;i<=122;i++) {
if(frequency[i] != 0)
printf("%c occurs %d times\n", str[i], count[i]);
}

Why I am getting extra chars while filling my char array in C?

I am trying to write an application in C and I have a problem: I have some unwanted chars in my string2 array in the code part below:
#include <stdio.h>
#include <string.h>
#define max_len 100
int main() {
char string1[max_len], string2[max_len], string3[max_len], temp[max_len];
int m, n, i, j, k, min_str_len;
puts("Enter your first word: ");
gets(string1);
puts("Enter your second word: ");
gets(string2);
m = strlen(string1);
n = strlen(string2);
min_str_len = ((m < n) ? m : n);
for (i = 0; i <= m; i++) {
for (j = 0; j <= n; j++) {
for (k = 0; k <= min_str_len; k++) {
if (string1[i] == string2[j]) {
//printf("%s",string2[j]);
temp[k] = string2[j];
break;
}
...
}
}
}
So you see here a part of my code. I am assigning "placozoa" as string1, and "placement" as string2. Please see the line: //printf("%s",string2[j]); When I make this line active, I see:
I did not understand why [] and ' characters are included in string2, I was just expecting to see "plac" there in the output.. The weird thing is, I am printing string2 array right after getting from the user (under gets(string2); line), and I see it is "placement" there.
What is happening in the middle, where is my mistake?
In your print statement, printf("%s",string2[j]); use %c instead of %s,
Because %s always try to convert the printing item to string. And to do that, your compiler has added a null char at the end of it.
So what actually happening right now,
when j == 0, string2[j] is equal to 'p' as a single charcter, but as string it becomes "p\0" where \0 is the null character which means the end of a string.
So, I think, just printing as a single character using %c (character) will solve the problem.

printf not printing last character

I'm making a simple code for simulating Caesar's cypher and I'm having a weird bug where, although the output string fraseout[] is formed correctly and will print correctly at the very last print it gets it's last character trimmed. Why is this happening?
#include <stdio.h>
#include <string.h>
#include <math.h>
int main (void)
{
printf("Insira a frase:\n");
char frase [256];
scanf("%s", frase);
int size = (int)strlen(frase);
printf("Insira o tamanho da divergência: \n");
int diff = 0;
scanf("%i", &diff);
char fraseout [size];
int i = 0;
for (i = 0; i<=size-1; i++)
{
int val = (int)frase[i];
if (val + diff > 126)
{
val = 31+diff-(126-val);
}
else if (val +diff < 32)
{
val = 127 + diff+(val-32);
}
else
{
val +=diff;
}
fraseout [i] = (char)val;
}
printf("\"%s\" -> \"%s\"\n", frase, fraseout);
return 0;
}
fraseout is not long enough to hold the NULL terminating byte, so you need to make it one bigger:
char fraseout [size+1];
Also, after building fraseout, you need to make sure it's NULL terminated, otherwise you'll print garbage:
fraseout[size] = '\0';
There are two related points,
Need to take the size as strlen()+ 1, as strlen() does not take into account the terminating null.
Need to make the fraseout[i], the last element as 0 or '\0' to make it usable as a string.

Resources