I am doing coding exercise in HackerRank. In the Variable Sized Arrays exercise of C++, I tried to do it with C, but I couldn't get it right.
My code sometimes pass the simple test case 0, but sometimes not. The code was exactly the same but came out with different answer.
int main() {
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
int n, q;
scanf("%d%d", &n, &q);
int *p_arr[n];
if (n > 0) {
for (int i = 0; i < n; i++) {
int tmp;
scanf("%d", &tmp);
int tmp_arr[tmp];
p_arr[i] = tmp_arr;
for (int j = 0; j < tmp; j++) {
int value;
scanf("%d", &value);
p_arr[i][j] = value;
printf("%d ", p_arr[i][j]);
}
printf("\n");
}
}
if (q > 0) {
for (int i = 0; i < q; i++) {
int row, col;
scanf("%d%d", &row, &col);
printf ("%d %d\n", row, col);
int answer = p_arr[row][col];
printf("%d\n", answer);
}
}
return 0;
}
This was the wrong answer I got
1 5 4
1 2 8 9 3
0 1
21973
1 3
32764
I didn't know where the 21973 and 32764 came from.
This was the answer I expected
1 5 4
1 2 8 9 3
0 1
5
1 3
9
Sometimes I got the wrong answer, sometimes I got the correct. Why was that?
Thanks a lot!
Continuing from the comments, if the exercise involves a Variable Length Array, then it should be written in C because the C++ standard does not provide VLAs (and they have been made optional beginning in C11 after being added with C99)
The primary problem with your code (aside from a complete failure to allocate the inputs) is that it invokes Undefined Behavior because int tmp_arr[tmp] goes out of scope at the end of the for loop. What you assign with p_arr[i] = tmp_arr; no longer exists outside the loop because tmp_arr no longer exists. Any attempt to access a value after it has gone out of scope invokes Undefined Behavior, see Undefined, unspecified and implementation-defined behavior
Every time you handle input, you must validate the input succeeded and the value obtained is within a valid range. For instance both n and q must be positive values. Using scanf you could do (minimally)
if (scanf("%d%d", &n, &q) != 2 || n <= 0 || q <= 0) {
fputs ("error: invalid format or value.\n", stderr);
return 1;
}
The above validates that 2 inputs were received and that both are positive values.
In order to preserve the pointer assigned with p_arr[i] = tmp_arr;, tmp_arr must be an allocated type to handle an unknown tmp number of elements, or it must be declared outside the loop (and large enough to handle all anticipated values -- which given that tmp is read as input -- doesn't seem like the intended approach). You cannot declare tmp_arr static either as there would only be one instance and assigning it repeatedly to p_arr[i] would leave all elements of p_arr[i] pointing to the same place.
Simply allocate for tmp_arr and then the assignment to p_arr[i] will survive for the life of the program or until it is freed, e.g.
int *tmp_arr = calloc (tmp, sizeof *tmp_arr); /* allocate */
if (!tmp_arr) { /* validate every allocation */
perror ("calloc-tmp_arr");
return 1;
}
p_arr[i] = tmp_arr;
(note: calloc was used above to zero the new memory allocated. You can use malloc instead since the code assigns to each element)
Putting it altogether and adding (minimal) validation, you could do something similar to:
#include <stdio.h>
#include <stdlib.h>
int main (void) {
int n, q; /* validate EVERY input */
if (scanf("%d%d", &n, &q) != 2 || n <= 0 || q <= 0) {
fputs ("error: invalid format or value.\n", stderr);
return 1;
}
int *p_arr[n]; /* array of n-pointers to int */
for (int i = 0; i < n; i++) {
int tmp;
if (scanf("%d", &tmp) != 1 || tmp <= 0) { /* validate! */
fputs ("error: invalid input - tmp.\n", stderr);
return 1;
}
int *tmp_arr = calloc (tmp, sizeof *tmp_arr); /* allocate */
if (!tmp_arr) { /* validate every allocation */
perror ("calloc-tmp_arr");
return 1;
}
p_arr[i] = tmp_arr;
for (int j = 0; j < tmp; j++) {
int value;
if (scanf("%d", &value) != 1) { /* validate! */
fputs ("error: invalid input - value.\n", stderr);
return 1;
}
p_arr[i][j] = value;
printf ("%d ", p_arr[i][j]);
}
putchar ('\n'); /* no need to printf a single-character */
}
for (int i = 0; i < q; i++) {
int row, col; /* validate! */
if (scanf ("%d%d", &row, &col) != 2 || row < 0 || col < 0) {
fputs ("error: invalid input, row or col.\n", stderr);
return 1;
}
printf ("%d %d\n%d\n", row, col, p_arr[row][col]);
}
for (int i = 0; i < n; i++)
free (p_arr[i]);
return 0;
}
(Note: untested as no hackerrank input was provided)
Look things over and let me know if you have further questions.
Related
Example: input: 420 50 -4
output: Numbers 3
Positive 2
Negative 1
and also for the same code:
input: 420 50 -4 7
output: Numbers 4
Positive 3
Negative 1
#include<stdio.h>
#define N 2
int main()
{
int a[N], i=0, n=0, k=0, z=0;
for(i=0; i<N; i++)
{
scanf("%d" , &a[i]);
if((a[i] >= -10000 && a[i] <= 10000 ))
n++;
if(a[i]>0)
k++;
if(a[i]<0)
z++;
}
printf("Numbers:%d \n", n);
printf("Positive:%d \n", k);
printf("Negative:%d \n", z);
return 0;
}
new issue
So the idea is this, I need my programm(mostly done by yano here) to only be able to load numbers ranging for -10000 to 10000 including border numbers, if other numbers would be loaded, the program should print the correct numbers, and ignore the incorrect (more like remove from array and replacing the element with the rest, which is correct, whilst reducing the total number of elements in the array)
example
input 140 -154161 20 30
output 140, 20, 30
Error: Input is outside interval!"
#include <stdio.h>
#include <stdlib.h>
#define INITIAL_SIZE 10
void
printArray (const int *myArray, size_t numsEntered)
{
int i, c = 0, k = 0, z = 0, s=0, l=0, sum=0, max, min;
float pk, pz, ps, pl, prumer;
for (size_t i = 0; i < numsEntered; i++) //does math
{
sum = sum + myArray[i];
if (i)
printf (", ");
printf ("%i", myArray[i]);
if ((myArray[i] >= -10000 && myArray[i] <= 10000))
c++;
if (myArray[i] > 0)
k++;
if (myArray[i] < 0)
z++;
if(myArray[i]%2==0)
s++;
else
l++;
max = myArray[0];
min = myArray[0];
if(myArray[i] > max)
{
max = myArray[i];
}
if(myArray[i] < min)
{
min = myArray[i];
}
}
if ((myArray[i] >= -10000 && myArray[i] <= 10000)) //checks if arrays are in range
{
prumer=(float) sum/2;
pk = (float) k / c;
pz = (float) z / c;
ps = (float) s / c;
pl = (float) l / c;
printf ("\n");
printf ("Pocet cisel: %d\n", c);
printf ("Pocet kladnych: %d\n", k);
printf ("Pocet zapornych: %d\n", z);
printf ("Procento kladnych: %.2lf\n", pk);
printf ("Procento zapronych: %.2lf\n", pz);
printf("Pocet sudych: %d\n", s);
printf("Pocet lichych: %d\n", l);
printf ("Procento sudych: %.2lf\n", ps);
printf ("Procento lichych: %.2lf\n", pl);
printf("Prumer: %.2lf\n", prumer );
printf("Maximum: %d\n", max);
printf("Minimum: %d\n", min);
}
if (myArray[0]<-10000 || myArray[0]>10000) //checks if first element is in wrong range
programm prints arror and returns 0
{
printf("\n");
printf ("Error: Vstup je mimo interval!");
}
}
int
main ()
{
int lastArray = 0, end = 0, b = 0, i=0;
size_t arraySize = INITIAL_SIZE;
size_t numsEnteredSoFar = 0;
int *myArray = malloc (sizeof (*myArray) * arraySize);// initially make room for 10
if (myArray == NULL)
exit (-1);
while (1)
{
int curEntry, size = sizeof (myArray) / sizeof (int);
char ch;
if (scanf ("%d", &curEntry) == 1)
{
b = curEntry;
end = numsEnteredSoFar;
ch = fgetc (stdin);
myArray[numsEnteredSoFar++] = curEntry;
if (numsEnteredSoFar == arraySize)
{
arraySize += INITIAL_SIZE;
int *temp = realloc (myArray, arraySize * sizeof (*myArray));
if (temp == NULL)
{
fprintf (stderr, "out of memory\n");
exit (-1);
}
else
{
myArray = temp;
}
}
}
for (size_t i = 0; i < numsEnteredSoFar; i++)
if((myArray[i]<-10000 || myArray[i]>10000)) //checks if input is in range if not exits
{
if (i) //my attempt for making this work
printf (", ");
printf ("%i", myArray[i]);
printf ("\n");
printf ("Error: Vstup je mimo interval!");
exit (-1);
}
if (ch == 10)
{
break;
}
}
printArray (myArray, numsEnteredSoFar);
free (myArray);
return 0;
}
There are several ways to solve this problem:
Declare an array that's large enough to accommodate the largest conceivable size of your data.
Include a size at the beginning of your data, and use that to malloc your array.
Use a data structure that doesn't depend on a fixed size, such as a linked list.
This example allows the user to enter numbers "indefinitely" without the need for prompting how many to enter. Of course, your computer only has so much RAM, so there is a limit, but not a practical limit. Essentially, you need to choose an initial size, then allocate more space dynamically when that size is reached.
#include <stdio.h>
#include <stdlib.h>
#define INITIAL_SIZE 10
void printArray(const int* myArray, size_t numsEntered)
{
for (size_t i=0; i<numsEntered; i++)
{
printf("myArray[%zu] = %d\n", i, myArray[i]);
}
}
int main(void)
{
size_t arraySize = INITIAL_SIZE;
size_t numsEnteredSoFar = 0;
int* myArray = malloc(sizeof(*myArray) * arraySize); // initially make room for 10
if (myArray == NULL) exit(-1); // whoops, malloc failed, handle this error how you want
while(1)
{
int curEntry;
printf("enter a number, or 'q' to quit: ");
if (scanf("%d", &curEntry) == 1)
{
// store in the array, increment number of entries
myArray[numsEnteredSoFar++] = curEntry;
// here you can check for positives and negatives, or
// wait to do that at the end. The point of this example
// is to show how to dynamically increase memory allocation
// during runtime.
if (numsEnteredSoFar == arraySize)
{
puts("Array limit reached, reallocing");
// we've reached our limit, need to allocate more memory to continue.
// The expansion strategy is up to you, I'll just continue to add
// INITIAL_SIZE
arraySize += INITIAL_SIZE;
int* temp = realloc(myArray, arraySize * sizeof(*myArray));
if (temp == NULL)
{
// uh oh, out of memory, handle this error as you want. I'll just
// print an error and bomb out
fprintf(stderr, "out of memory\n");
exit(-1);
}
else
{
// realloc succeeded, we can now safely assign temp to our main array
myArray = temp;
}
}
}
else
{
// the user entered 'q' (or anything else that didn't match an int), we're done
break;
}
}
// print the array just to show it worked. Instead, here you can
// loop through and do your comparisons for positive and negative,
// or you can continue to track that after each entry as you've
// shown in your code
printArray(myArray, numsEnteredSoFar);
free(myArray);
return 0;
}
Demo
Several parts to the answer.
Either declare a nice, big array, bigger than you'll ever need, or, prompt the user for the size, and then use that user-entered size to declare or allocate the array. (This is a popular strategy, but it's a lousy user experience, since the user shouldn't need to know or say how many numbers they're going to enter.)
Check the return value of scanf. If the return value isn't 1, this means that scanf failed, and didn't input a number. You can take this as an indication that the user stopped entering numbers.
Have two variables: the size of the array, and the number of numbers actually entered. You set the number of numbers actually entered by noticing when scanf failed. Then, later, when you work with the date in the array, you don't do for(i = 0; i < N; i++), you do for(i = 0; i < number_of_numbers; i++).
If you don't want to ask the user to explicitly enter the number of numbers, and you don't want to pick a "big enough" size in advance (either because you don't want to waste memory, or because you want to make sure the user can enter a lot of inout, potentially more than any number you picked), it's possible to dynamically reallocate an array bigger and bigger as the user enters more and more data, but that's an advanced topic.
my code problem:
this code only lets me input one command then jumps out of the loop without even inputting 'quit'
The problem is to parse a series of commands that instruct a robot arm on how to manipulate blocks that lie on a flat table. Initially, there are n blocks on the table (numbered from 0 to n − 1) with block bi adjacent to block bi+1 for all 0 ≤ i < n − 1 as shown in the diagram below:
https://ibb.co/WpWQBYT
The valid commands for the robot arm that manipulates blocks are:
• move a onto b
where a and b are block numbers, puts block a onto block b after returning any blocks that are stacked on top of blocks a and b to their initial positions.
• move a over b
puts block a onto the top of the stack containing block b, after returning any blocks that are stacked on top of block a to their initial positions.
• pile a onto b
moves the pile of blocks consisting of block a, and any blocks that are stacked above block a, onto block b. All blocks on top of block b are moved to their initial positions prior to the pile taking place. The blocks stacked above block a retain their order when moved.
• pile a over b
puts the pile of blocks consisting of block a, and any blocks that are stacked above block a, onto the top of the stack containing block b. The blocks stacked above block a retain their original order when moved.
• quit
terminates manipulations in the block world. Any command in which a = b or in which a and b are in the same stack of blocks is an illegal command. All illegal commands should be ignored and should have no effect on the configuration of blocks.
Input:
https://ibb.co/pWJ9c7Q
Output:
https://ibb.co/Nt03mm3
[I only type the code of the first command for now.]
my code:
#include<stdio.h>
#include<string.h>
int main(){
int noi=0;
printf("please input n:");
int n;
scanf(" %d",&n);
int arr[n][n];
int i,j;
for(i=0;i<n;i++){
for(j=0;j<n;j++){
arr[i][j]=-1;
}
arr[i][0]=i;
}
char str1[5],str2[5];
int s,d;
while(strcmp(str1,"quit")!=0){
s=0;
d=0;
while(!(s>=1&&s<=n&&d>=1&&d<=n)){
scanf(" %s %d %s %d",str1,&s,str2,&d);
}
if(strcmp(str1,"move")==0){
if(strcmp(str2,"onto"==0)){
//empty s
for(i=0;i<n&&arr[s][i]!=-1;i++){
arr[arr[s][i]][0]=arr[s][i];
arr[s][i]=-1;
}
//empty d
for(i=0;i<n&&arr[d][i]!=-1;i++){
arr[arr[d][i]][0]=arr[d][i];
arr[d][i]=-1;
}
//now move s to d
i=1;
while(arr[d][i]!=-1){
i++;
}
arr[d][i]=arr[s][0];
arr[s][0]=-1;
}else if(strcmp(str2,"over")==0){
}else{
continue;
}
}else if(strcmp(str2,"pile")==0){
}else{
continue;
}
}
//print results
for(i=0;i<n;i++){
printf("%d:",i);
for(j=0;j<n&&arr[i][j]!=-1;j++){
printf("%d ",arr[i][j]);
}
printf("\n");
}
}
There are an extremely large number of errors in your code. Probably the one of the largest impediments to recognizing the problems in your code, while not an error, is the lack of spacing in your code. Scrunching everything together makes your code very difficult to read (especially for older eyes). Open the spacing on your code up a bit.
As mentioned in the comments above, your first show-stopping problem is the use of str1 while it is uninitialized. That invokes undefined behavior and then defined operation of your code is over at that point. Your code could SegFault, appear to work normally, or anything in between.
When you are taking user-input, it is recommended you use a line-oriented input function like fgets() or POSIX getline(). That one change avoids a large number of pitfalls associated with attempting to take user-input with a formatted-input function like scanf(). If you don't know what each of the pitfalls are associated with its use -- don't use it for user input. 9 out of 10 of the user input questions on this site relate to the misuse of scanf().
Additionally, Don't Skimp On Buffer Size!!. What happens if the user enters "iskabibble" instead of "quit"? How are the characters that do not fit in str1[5] handled? What if the cat steps on the keyboard and 100 characters are entered? It's better to be 10,000 characters too long, than one character too short. Take input with fgets() and a sufficiently sized buffer, and then parse the values needed with sscanf() instead of trying to do both with scanf(), e.g.
#define MAXC 512 /* if you need a constant, #define one (or more)
* ( don't skimp on buffer size!! )
*/
int main (void) {
char buf[MAXC]; /* buffer to store all user input */
int n; /* if possible, declare variables at beginning of scope */
fputs ("please input n for (n x n array): ", stdout);
if (!fgets (buf, MAXC, stdin)) { /* read all user input with fgets() */
puts ("(user canceled input)");
return 0;
}
if (sscanf (buf, "%d", &n) != 1) { /* validate every conversion */
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
Reusing a single buffer to handle user-input simplifies things greatly.
While it is fine to use a VLA (Variable Length Array) for practice problems, be aware compilers are not required to support them from C11 forward, and none were supported before C99. Better to dynamically allocate for production code.
Your variable declarations should be in the scope where the variables are needed. This helps prevent variable shadowing of common variables such as i, j, etc.. 300 lines down in your code. For example, loop variables can be declared as part of the loop declaration so long as they are not needed outside the loop, e.g.
int arr[n][n]; /* VLA's are an 'optional' feature since C11 */
for (int i = 0; i < n; i++) { /* i, j can be decalred with loop scope */
for (int j = 0; j < n; j++) {
arr[i][j] = -1;
}
arr[i][0] = i;
}
When you need to user to enter specific input, better to loop continually until the user provides valid input (respecting their ability to cancel input by generating a manual EOF with Ctrl + d, or Ctrl + z on windows). For example where str1, s, str2 and d are needed:
while (strcmp (buf, "quit")) { /* loop until quit */
char str1[MAXC] = "", str2[MAXC] = "";
int s = 0, d = 0;
while (1) { /* loop continually */
fputs ("enter str1 s str2 d: ", stdout); /* prompt */
if (!fgets (buf, MAXC, stdin)) { /* read / validate input */
puts ("(user canceled input)");
return 0;
}
buf[strcspn (buf, "\n")] = 0; /* trim '\n' from end of buf */
if (strcmp (buf, "quit") == 0) /* if "quit", break */
break;
/* parse and validate separate values, always protect array bounds */
if (sscanf (buf, "%511s %d %511s %d", str1, &s, str2, &d) != 4) {
fputs (" error: invalid format or integer input.\n", stderr);
continue;
} /* validate range of integers (negated conditions are confusing) */
if ((0 <= s && s < n) && (0 <= d && d < n))
break; /* exit loop on good input */
else /* otherwise, handle error */
fputs (" error: value for s or d out of range.\n", stderr);
}
(note: fgets() reads and includes the '\n' generated by the user pressing Enter, so before comparing for "quit" you will need to remove the newline with strcspn())
Since str1 and str2 are parsed from buf using sscanf() there is no '\n' to remove. However, when using sscanf() you must use the field-width modifier to protect the array bounds from overrun -- otherwise the use of scanf() or sscanf() to fill the character array is no safer than gets(), see: Why gets() is so dangerous it should never be used!
if (strcmp (str1, "move") == 0) { /* handle move */
if (strcmp (str2, "onto") == 0) { /* onto? */
int i; /* declare i in scope needed */
// empty s
for (i = 0; i < n && arr[s][i] != -1; i++) {
arr[arr[s][i]][0] = arr[s][i];
arr[s][i] = -1;
}
// empty d
for (i = 0; i < n && arr[d][i] != -1; i++){
arr[arr[d][i]][0] = arr[d][i];
arr[d][i] = -1;
}
// now move s to d
i = 1;
while (arr[d][i] != -1) {
i++;
}
arr[d][i] = arr[s][0];
arr[s][0] = -1;
}
else if (strcmp (str2, "over") == 0) {
(void)str2; /* no-op prevents empty scope */
}
else {
continue;
}
}
else if (strcmp (str2, "pile") == 0) {
(void)str2;
}
else {
continue;
}
(note: the final else is not needed)
Complete Code
While I am still unclear on what your logic is supposed to do, handing the input can be done as shown above. Fixing the logic is left to you.
#include <stdio.h>
#include <string.h>
#define MAXC 512 /* if you need a constant, #define one (or more)
* ( don't skimp on buffer size!! )
*/
int main (void) {
char buf[MAXC]; /* buffer to store all user input */
int n; /* if possible, declare variables at beginning of scope */
fputs ("please input n for (n x n array): ", stdout);
if (!fgets (buf, MAXC, stdin)) { /* read all user input with fgets() */
puts ("(user canceled input)");
return 0;
}
if (sscanf (buf, "%d", &n) != 1) { /* validate every conversion */
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
int arr[n][n]; /* VLA's are an 'optional' feature since C11 */
for (int i = 0; i < n; i++) { /* i, j can be decalred with loop scope */
for (int j = 0; j < n; j++) {
arr[i][j] = -1;
}
arr[i][0] = i;
}
while (strcmp (buf, "quit")) { /* loop until quit */
char str1[MAXC] = "", str2[MAXC] = "";
int s = 0, d = 0;
while (1) { /* loop continually */
fputs ("enter str1 s str2 d: ", stdout); /* prompt */
if (!fgets (buf, MAXC, stdin)) { /* read / validate input */
puts ("(user canceled input)");
return 0;
}
buf[strcspn (buf, "\n")] = 0; /* trim '\n' from end of buf */
if (strcmp (buf, "quit") == 0) /* if "quit", break */
break;
/* parse and validate separate values, always protect array bounds */
if (sscanf (buf, "%511s %d %511s %d", str1, &s, str2, &d) != 4) {
fputs (" error: invalid format or integer input.\n", stderr);
continue;
} /* validate range of integers (negated conditions are confusing) */
if ((0 <= s && s < n) && (0 <= d && d < n))
break; /* exit loop on good input */
else /* otherwise, handle error */
fputs (" error: value for s or d out of range.\n", stderr);
}
if (strcmp (str1, "move") == 0) { /* handle move */
if (strcmp (str2, "onto") == 0) { /* onto? */
int i; /* declare i in scope needed */
// empty s
for (i = 0; i < n && arr[s][i] != -1; i++) {
arr[arr[s][i]][0] = arr[s][i];
arr[s][i] = -1;
}
// empty d
for (i = 0; i < n && arr[d][i] != -1; i++){
arr[arr[d][i]][0] = arr[d][i];
arr[d][i] = -1;
}
// now move s to d
i = 1;
while (arr[d][i] != -1) {
i++;
}
arr[d][i] = arr[s][0];
arr[s][0] = -1;
}
else if (strcmp (str2, "over") == 0) {
(void)str2; /* no-op prevents empty scope */
}
else {
continue;
}
}
else if (strcmp (str2, "pile") == 0) {
(void)str2;
}
else {
continue;
}
}
// print results
for (int i = 0; i < n; i++) {
printf ("%d:\n", i);
for (int j = 0; j < n; j++) {
if (arr[i][j] != -1)
printf (" % 3d", arr[i][j]);
else
fputs (" [ ]", stdout);
}
putchar ('\n');
}
}
Example Use/Output
With intentional errors in input:
$ ./bin/vla_quit
please input n for (n x n array): 5
enter str1 s str2 d: move 2 onto 3
enter str1 s str2 d: move bananas onto gorillas
error: invalid format or integer input.
enter str1 s str2 d: move 1 onto 4
enter str1 s str2 d: move -1 onto 2
error: value for s or d out of range.
enter str1 s str2 d: move 0 onto 2
enter str1 s str2 d: quit
0:
[ ] [ ] [ ] [ ] [ ]
1:
[ ] [ ] [ ] [ ] [ ]
2:
[ ] [ ] [ ] [ ] [ ]
3:
[ ] [ ] [ ] [ ] [ ]
4:
[ ] [ ] [ ] [ ] [ ]
Always compile with warnings-enabled, and do not accept code until it compiles without warning. To enable warnings add -Wall -Wextra -pedantic to your gcc/clang compile string (also consider adding -Wshadow to warn on shadowed variables). For VS (cl.exe on windows), use /W3. All other compilers will have similar options. Read and understand each warning -- then go fix it. They will identify any problems, and the exact line on which they occur. You can learn a lot by listening to what your compiler is telling you.
Let me know if you have further questions.
A given string is palindrome, you need to state that it is even palindrome (palindrome with even length) or odd palindrome (palindrome with odd length) otherwise return No.
This code i write but not get true output
#include<string.h>
#include <stdio.h>
int main(){
int n ;
char s[100000],b[100000];
int count=0,d,h,i,t,j;
if(count<1)
{
scanf("%d", &n);
if(n<=50)
{
for(t=1;t<=n;t++)
{
i=0,j=0,h=0;
scanf("%s", s);
h=strlen(s)-1;
if(h>=1&&h<=100000)
{
for(i=0,j=h;i<=h&&j>=0; j--,i++)
{
b[i]=s[j];
}
if(strcmp(s,b)==0)
{
if(h%2==0)
{
printf("YES EVEN");
printf("\n");
}
else
{
printf("YES ODD");
printf("\n");
}
}
else{
printf("NO");
printf("\n");
}
}
}
}
count++;
}
return 0;
}
#include<string.h>
#include <stdio.h>
int main(){
int n ;
char s[100000],b[100000];
int count=0,d,h,i,t,j;
if(count<1)
{
scanf("%d", &n);
if(n<=50)
{
for(t=1;t<=n;t++)
{
i=0,j=0,h=0;
scanf("%s", s);
h=strlen(s)-1;
if(h>=1&&h<=100000)
{
for(i=0,j=h;i<=h&&j>=0; j--,i++)
{
b[i]=s[j];
}
if(strcmp(s,b)==0)
{
if(h%2==0)
{
printf("YES EVEN");
printf("\n");
}
else
{
printf("YES ODD");
printf("\n");
}
}
else{
printf("NO");
printf("\n");
}
}
}
}
count++;
}
return 0;
}
Forget about syntax error only find logical error.
I expect the output is
Input
3
abc
abba
aba
Your Code's Output
NO
YESODD
NO
Expected Correct Output
NO
YESEVEN
YESODD
I get true result when i provide one string not more than that
but where is error.
When creating the string b you forget to add the terminating character \0
While checking for even you use h%2. But h is strlen(s)-1. So you need to set odd if h%2 == 0
Relevant changes are shown below
for(i=0,j=h;i<=h&&j>=0; j--,i++)
{
b[i]=s[j];
}
b[h+1] = '\0';
if(strcmp(s,b)==0)
{
if(h%2!=0)
{
printf("YES EVEN");
printf("\n");
}
else
{
printf("YES ODD");
printf("\n");
}
}
Forget about syntax error only find logical error.
I find this sort of statement very wrong. Unless you fix the syntax, you cannot look at it logically. Also proper indentation really helps in debugging the code and finding errors on your own.
You have a number of problems, but your primary problem is in your reversal. You attempt to reverse with:
h=strlen(s)-1;
if(h>=1&&h<=100000){
for(i=0,j=h;i<=h&&j>=0; j--,i++) {
b[i]=s[j];
}
This will fail for strlen(s) == 1, does not ensure nul-termination and because you use h=strlen(s)-1;, your h in if (h % 2 == 0) results in the opposite determination of EVEN and ODD. Instead you need:
#define MAXC 100000 /* if you need a constant, #define one (or more) */
...
h = strlen (s); /* h must be strlen(s) - not - 1 */
if (h >= 1 && h < MAXC) { /* now loop j=h-1; j < h times */
for (i = 0, j = h-1; i < h && j >= 0; j--,i++)
b[i] = s[j];
b[i] = 0; /* and ensure b is nul-terminated */
(note: adequately spaced code is much easier to read and debug)
Next, you fail to validate the return of every call to scanf, instead, blindly using the variables without any indication of whether your input succeeded -- a recipe for Undefined Behavior. You must validate EVERY user input, e.g.
if (scanf ("%d", &n) != 1 || n > 50) {
fputs ("error: invalid integer or out-of-range.\n", stderr);
return 1;
}
while (n-- && scanf ("%s", s) == 1) {
Simply choosing a logical factoring of your code eliminates the need altogether for variables t and d. Note, your conditions on n are (1) it's valid, and (2) it's 50 or less. Those can be combined into a single check. The same goes for looping n times while reading words into s.
Making those changes, your code simplifies to:
#include <stdio.h>
#define MAXC 100000 /* if you need a constant, #define one (or more) */
int main (void)
{
char s[MAXC];
int n;
if (scanf ("%d", &n) != 1 || n > 50) {
fputs ("error: invalid integer or out-of-range.\n", stderr);
return 1;
}
while (n-- && scanf ("%s", s) == 1) {
char b[MAXC]; /* b is only needed within loop */
int h = strlen (s), i = 0, j; /* as are h, i, j, no - 1 for h */
if (h >= 1 && h < MAXC) { /* now loop j=h-1; j < h times */
for (i = 0, j = h-1; i < h && j >= 0; j--,i++)
b[i] = s[j];
b[i] = 0; /* and ensure b is nul-terminated */
if (strcmp (s, b) == 0) {
if (h % 2 == 0)
printf ("YES EVEN\n");
else
printf ("YES ODD\n");
}
else
printf ("NO\n");
}
}
return 0;
}
Which now provides the palindrome check and ODD or EVEN length output you were looking for, e.g.
Example Use/Output
$ echo "5 abcba abccba abcdba a aa" | ./bin/pdromerefmt
YES ODD
YES EVEN
NO
YES ODD
YES EVEN
You should further protect the array bounds of s by including the field-width modifier for the "%s" conversion, e.g. "%99999s" which eliminates the need to check h <= 100000 (which would have already invoked Undefined Behavior if input was 100000 characters or greater). There is no need to check h >= 1 as the loop limits do nothing with h = 0 -- but do ensure an empty-string.
With the further tweaks and array bounds protections, your loop simplifies to:
while (n-- && scanf ("%99999s", s) == 1) {
char b[MAXC]; /* b is only needed within loop */
int h = strlen(s), i = 0, j = h;/* as are h, i, j, no -1 for h */
while (j--) /* must loop j times, regardless */
b[i++] = s[j]; /* reversing characters in s in b */
b[i] = 0; /* and ensure b is nul-terminated */
if (strcmp (s, b) == 0) {
if (h % 2 == 0)
printf ("YES EVEN\n");
else
printf ("YES ODD\n");
}
else
printf ("NO\n");
}
Forget about syntax error only find logical error.
That's what pencils and papers (or your rubber duck, maybe) are for, to figure out an algorithm and logically follow its steps. You have a complete program, though, and a large number of tests to try it. Now it's time to eradicate every single bug you can find, starting from syntax errors, which are "easily" detectable at compile time.
There are already enough answers about the flaws in the posted code, but there is at least one thing not yet covered, which isn't really a bug or a logic mistake, though.
The posted algorithm, for every test case, does the following:
Read a word (with scanf).
Find it size (with strlen).
Create a reversed copy of it (using a for loop).
Compare the copy with the original to check the palindromicity (with strcmp).
Why all those copies and array traversals? Once you know the length of the word you can just compare the left side of the string with the right side.
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#define MAX_CHARS_IN_STR 100000
#define MAX_N_TESTS 50
// Performs the check without copying the the string
// length: size of the word
bool is_palindrome(size_t length, const char *str);
#define STRINGIFY_IMPL(x) #x
#define STRINGIFY(x) STRINGIFY_IMPL(x)
#define STR_WIDTH_FMT(x) "%" STRINGIFY(x) "s"
int main(void)
{
int n_words;
if ( scanf("%d", &n_words) != 1 || n_words < 1 || n_words > MAX_N_TESTS)
{
fprintf(stderr, "Error: the input is not a valid integer between 1 and %d.",
MAX_N_TESTS);
return 1;
}
int n_chars;
// Allocates an array big enough (including the null-terminator)
char word[MAX_CHARS_IN_STR + 1];
// It will use an array of two pointers instead of another if-else
const char *even_or_odd_str[] = { "IS EVEN", "IS ODD" };
while ( n_words-- )
{
// consume whitespace characters left in the input
scanf(" ");
// reads the string up to its maximum width or until the first whitespace.
// The macro expands to "%100000s" and that literal will be concatenated to "%n",
// which returns the number of characters read.
if ( scanf(STR_WIDTH_FMT(MAX_CHARS_IN_STR) "%n", word, &n_chars) != 1 )
{
fputs("Error: unable to read word.", stderr);
break;
}
if ( is_palindrome(n_chars, word) )
puts(even_or_odd_str[n_chars % 2]);
else
puts("NO");
}
}
bool is_palindrome(size_t n, const char *str)
{
assert(n && str);
size_t i = 0, j = n - 1;
while ( i < j && str[i] == str[j] )
{
++i;
--j;
}
// It's a palindrome only if the two indices met halfway
return i >= j;
}
My program should first ask for the number of integers to read and dynamically allocate an array just big enough to hold the number of values I read. Then, I need to categorize these values into odd and even.
This is the code I've tried
#include <stdio.h>
#include <stdlib.h>
int main(void){
//declare variables
int i; //loop counter
int count; //integer amount from user
int j = 0; int k = 0;
// read in integer count from user
printf("enter the amount of numbers: ");
scanf("%d", &count);
// declare pointer
int *number = malloc(sizeof(int)*count);
int *evens = malloc(sizeof(int)*count);
int *odds = malloc(sizeof(int)*count);
// declare variable
//int odds_count = 0;
//int evens_count = 0;
//loop to read in numbers from user
for (i=0; i<count; i++){
printf("enter number %02d: ",i+1);
scanf("%d",(number+i));
printf("you entered %d\n", *(number+i)); //--- entered values are correct here
if (*(number+i)% 2 ==0){
*(number+i) = *(evens+j);
j++;
//evens_count++;
} else {
*(number+i) = *(odds+k);
k++;
}
printf("you entered %d\n", *(number+i)); //---entered values become 0
}
//print array elements
printf("\nEntered array elements are:\n");
for(i=count;i>0;i--)
{
printf("%d ",*(number+i));
}
printf("\n");
// print out even numbers
printf("even numbers: ");
for (i=0;i<j;i++){
printf("%5d",*(evens+i));
}
printf("\n");
// print out odd numbers
printf("odd numbers: ");
for (i=0;i<k;i++){
printf("%5d",*(odds+i));
}
printf("\n");
return 0;
}
No matter what input I enter, the output only displays 0.
E.g:
Input- 1, 2, 3
Output-
Evens: 0
Odds: 0 0
Please help me with this. Thanks in advance!
While getting the input from user, try putting an '&' symbol before your variable name. I think that should work.
scanf("%d",&(number+i));
Happy coding :)
Your biggest issues regarding assigning values occurs when you attempt to assign evens[j] and odds[j] to numbers[i] before the elements of either evens or odds have been initialized. Following your call to malloc for each evens and odds the block of memory allocated contains whatever garbage values happen to be in that memory region at the time of allocation. malloc does not initialize the content of the memory in any way and leave the values indeterminate. If you want to both allocate and zero all bytes, you can use calloc instead of malloc.
This problem occurs here:
if (*(number+i)% 2 ==0){
*(number+i) = *(evens+j);
j++;
//evens_count++;
} else {
*(number+i) = *(odds+k);
k++;
}
Look carefully, you check whether numbers[i] is even/odd with % 2 == 0, but then attempt to overwrite the value at numbers[i] with either evens[j] or odds[k] -- this is backwards. The intent would be to assign the value in numbers[i] to either evens[j] or odds[k], e.g.
if (number[i] % 2 ==0){
evens[j] = number[i];
j++;
//evens_count++;
} else {
odds[k] = number[i];
k++;
}
Next, your use of variables is jumbled. You don't need all the different i, j, k counters declared at the beginning of main(). For the past 20 years, since C99, you can declare the loop variable within the for loop declaration itself. This eliminates the chance that your use of your loop variable will conflict with another use of i, j, k somewhere else in the program.
You have count, odd_count & even_count, those are the only counters you need.
Further, you need to VALIDATE every User Input and every Allocation. Otherwise, you risk invoking Undefined Behavior with the slip of a keystroke or when (not "if") an allocation returns NULL. Validate every critical step.
Putting those measures to use, you can simplify your declaration to:
int count, /* integer amount from user */
odd_count = 0, /* odd count (initialized zero) */
even_count = 0, /* even count (initialized zero)*/
*number, /* declare pointers */
*evens,
*odds;
You can validate your input with:
/* read in integer count from user (VALIDATE every input) */
printf("enter the amount of numbers: ");
if (scanf("%d", &count) != 1) {
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
...
for (int i = 0; i < count; i++) { /* loop count times for input */
printf ("enter number %2d: ", i + 1);
if (scanf ("%d", &number[i]) != 1) { /* validate EVERY input */
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
if (number[i] % 2 == 0) /* assign, increment evens count */
evens[even_count++] = number[i];
else /* same for odds */
odds[odd_count++] = number[i];
}
And you can validate your allocations:
/* allocate count integers each pointer (VALIDATE every allocation) */
if ((number = malloc (count * sizeof *number)) == NULL) {
perror ("malloc-number");
return 1;
}
if ((evens = malloc (count * sizeof *evens)) == NULL) {
perror ("malloc-evens");
return 1;
}
if ((odds = malloc (count * sizeof *odds)) == NULL) {
perror ("malloc-odds");
return 1;
}
Then it is simply a matter of looping i = 0; i < count to output the number, i = 0; i < even_count to output evens and finally i = 0; i < odd_count to output odds, e.g.
puts ("\n numbers\n--------"); /* output each array on its own */
for (int i = 0; i < count; i++)
printf ("%8d\n", number[i]);
puts ("\n evens\n--------");
for (int i = 0; i < even_count; i++)
printf ("%8d\n", evens[i]);
puts ("\n odds\n--------");
for (int i = 0; i < odd_count; i++)
printf ("%8d\n", odds[i]);
And Finally, you can output all 3 arrays at once with:
/* output all arrays together */
puts ("\nnumbers even odd\n-------- -------- --------");
for (int i = 0; i < count; i++) { /* loop printing number */
printf ("%8d", number[i]);
if (i < even_count) { /* if i < even_count */
printf (" %8d", evens[i]); /* output evens */
if (i < odd_count) /* if odds too, output them */
printf (" %8d\n", odds[i]);
else
putchar ('\n'); /* no more odds output '\n' */
}
else if (i < odd_count) /* if only odds left, output */
printf ("%18d\n", odds[i]);
else
putchar ('\n');
}
At the end, don't forget to free the memory you allocate, e.g.
free (number); /* don't forget to free what you allocated */
free (evens);
free (odds);
Putting it altogether, you could do:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int count, /* integer amount from user */
odd_count = 0, /* odd count (initialized zero) */
even_count = 0, /* even count (initialized zero)*/
*number, /* declare pointers */
*evens,
*odds;
/* read in integer count from user (VALIDATE every input) */
printf("enter the amount of numbers: ");
if (scanf("%d", &count) != 1) {
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
/* allocate count integers each pointer (VALIDATE every allocation) */
if ((number = malloc (count * sizeof *number)) == NULL) {
perror ("malloc-number");
return 1;
}
if ((evens = malloc (count * sizeof *evens)) == NULL) {
perror ("malloc-evens");
return 1;
}
if ((odds = malloc (count * sizeof *odds)) == NULL) {
perror ("malloc-odds");
return 1;
}
for (int i = 0; i < count; i++) { /* loop count times for input */
printf ("enter number %2d: ", i + 1);
if (scanf ("%d", &number[i]) != 1) { /* validate EVERY input */
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
if (number[i] % 2 == 0) /* assign, increment evens count */
evens[even_count++] = number[i];
else /* same for odds */
odds[odd_count++] = number[i];
}
puts ("\n numbers\n--------"); /* output each array on its own */
for (int i = 0; i < count; i++)
printf ("%8d\n", number[i]);
puts ("\n evens\n--------");
for (int i = 0; i < even_count; i++)
printf ("%8d\n", evens[i]);
puts ("\n odds\n--------");
for (int i = 0; i < odd_count; i++)
printf ("%8d\n", odds[i]);
/* output all arrays together */
puts ("\nnumbers even odd\n-------- -------- --------");
for (int i = 0; i < count; i++) { /* loop printing number */
printf ("%8d", number[i]);
if (i < even_count) { /* if i < even_count */
printf (" %8d", evens[i]); /* output evens */
if (i < odd_count) /* if odds too, output them */
printf (" %8d\n", odds[i]);
else
putchar ('\n'); /* no more odds output '\n' */
}
else if (i < odd_count) /* if only odds left, output */
printf ("%18d\n", odds[i]);
else
putchar ('\n');
}
free (number); /* don't forget to free what you allocated */
free (evens);
free (odds);
}
Example Use/Output
$ ./bin/number_evens_odds
enter the amount of numbers: 10
enter number 1: 21
enter number 2: 22
enter number 3: 23
enter number 4: 24
enter number 5: 119
enter number 6: 121
enter number 7: 131
enter number 8: 140
enter number 9: 141
enter number 10: 143
numbers
--------
21
22
23
24
119
121
131
140
141
143
evens
--------
22
24
140
odds
--------
21
23
119
121
131
141
143
numbers even odd
-------- -------- --------
21 22 21
22 24 23
23 140 119
24 121
119 131
121 141
131 143
140
141
143
Look things over and let me know if you have further questions.
I wrote a program that scans an unknown amount of integers into an array but when I run it, it print the last value it has gotten an infinite amount of times.
For example for the input: 1 2 3 4 5
The output would be 55555555555555555555555...
Why does this happen and how can I fix that?
My goal here is to create a array, for an instance {1, 2, 3, 4, 5} and then print what it scanned into the array, ONLY ONCE...
int *pSet = (int*) malloc(sizeof(int)); int i; int c;
printf("Please enter a stream of numbers to make a set out of them: ");
printf("\n");
scanf("%d", &c);
pSet[0] = c;
printf("%d ", c);
for(i = 1; c != EOF; i++) {
pSet = (int*) realloc(pSet, sizeof(int)*(i+1));
if(pSet == NULL) {
return FAIL;
}
scanf("%d", &c);
pSet[i] = c;
printf("%d ", c);
}
free(pSet);
Why does this happen (?) (print ... an infinite amount of times.)
Look at the loop terminating conditions c != EOF.
int c;
scanf("%d", &c);
for(i = 1; c != EOF; i++) { // Not good code
scanf("%d", &c);
}
EOF is some negative value, often -1. scanf("%d", &c) attempts to read user input and convert to an int. scanf() returns a 1,0,EOF depending on if it 1) succeeded, 2) failed to find numeric text or 3) end-of-file or input error occurred. Unfortunately code does not use that return value. Instead code used the number read, c and checked if that number read was the same as EOF.
how can I fix that?
Only loop when the return value of scanf() is as expected (1).
for(i = 1; scanf("%d", &c) == 1; i++) {
...
}
Putting this together with some other ideas
#include <stdio.h>
#include <stdio.h>
int main(void) {
printf("Please enter a stream of numbers to make a set out of them:\n");
int *pSet = NULL; // Start with no allocation
size_t i = 0;
int c;
for (i = 0; scanf("%d", &c) == 1; i++) {
// +--------------------------- No cast needed.
// v v----------v Use sizeof de-referenced pointer
void *p = realloc(pSet, sizeof *pSet * (i + 1));
if (p == NULL) {
free(pSet);
return EXIT_FAILURE;
}
pSet = p;
pSet[i] = c;
}
for (size_t j = 0; j < i; j++) {
printf("%d ", pSet[j]);
}
free(pSet);
return 0;
}
There are a number of problems.
1) Terminate the loop when scanf fails instead of using EOF. Do that by checking that the return value is 1 (i.e. the number of input items
successfully matched)
2) Don't allocate memory until it's needed
3) Never do realloc directly into the target pointer - always use a temp variable.
Fixing this your code could be:
#include <stdio.h>
int main(void) {
int *pSet = NULL;
printf("Please enter a stream of numbers to make a set out of them: ");
printf("\n");
int i = 0;
int c;
while (1) {
if (scanf("%d", &c) != 1)
{
printf("Terminating input loop\n");
break;
}
int* tmp = realloc(pSet, sizeof(int)*(i+1));
if(tmp == NULL) {
printf("oh dear...\n");
break;
}
pSet = tmp;
pSet[i++] = c;
printf("%d ", c);
}
for (int j=0; j < i; ++j) printf("%d\n", pSet[j]);
free(pSet);
return 0;
}
Input:
1 2 3 4 5 6 7 stop
Output:
Please enter a stream of numbers to make a set out of them:
1 2 3 4 5 6 7
Terminating input loop
1
2
3
4
5
6
7
You should stop your loop when scanf fails. According to the manual:
On success, [scanf] return[s] the number of input items successfully matched and assigned; this can be fewer than provided for, or even zero, in the event of an early matching failure.
The value EOF is returned if the end of input is reached before either the first successful conversion or a matching failure occurs. EOF is also returned if a read error occurs. [...]
So you can turn your for loop into a while one.
#include <stdio.h>
#include <stdlib.h>
#define FAIL 0
int main() {
int *pSet = (int*) malloc(sizeof(int));
int c;
int i=0;
printf("Please enter a stream of numbers to make a set out of them: ");
while(scanf("%d", &c) == 1) {
pSet[i] = c;
pSetNew = (int*) realloc(pSet, sizeof(int)*(i+1));
if(pSetNew == NULL) {
free(pSet);
return FAIL;
} else {
pSet = pSetNew;
}
printf("%d ", c);
i++;
}
free(pSet);
}
But if you want a more robust piece of code, I suggest you to retrieve the answer as a string (NULL-terminated array of char), and then parse it with dedicated functions like strtol which let you check if the whole string is a valid entry, and not only the first characters.
Note: HengLi fixed a potential memory leak in the code sample above