Variable value is reset inside a loop in C - c

I have a case in which I have to identify if a number is positive, negative or zero and count how many times each of these cases happen. The code I wrote is this:
#include
#include
#include
using namespace std;
int main(int argc, char *argv[])
{
char opcion = 's';
int positivos = 0;
int negativos = 0;
int ceros = 0;
//int ceros2 = 0;
int temporal;
do{
printf("Enter a number: ");
scanf("%d",&temporal);
if(temporal >= 0)
{
if(temporal==0)
{
ceros ++;
}
else
{
positivos ++;
}
}
if(temporal < 0)
{
negativos ++;
}
printf("Do you want to enter another number? (s/n)");
scanf("%s",&opcion);
}
while(opcion == 's' || opcion=='S');
printf("you have %d possitive numbers \n",positivos);
printf("you have %d negative numbers \n",negativos);
printf("you have %d zero \n",ceros);
return 0;
}
If I run the code as it is, the number of zeroes will always be zero, but if you uncoment the line 13 int ceros2 = 0; (my logic was "let's declare another initializaed variable and see what happens") then the program will count the zeroes as expected. Why do i have to declare a useless variable in order to the program make the count?
What is C compiler doing with the code that does not respect the value of the last declared and initialized variable unless you declare a new initialized variable?

You are asking scanf() to read in a C string, which, if the user types a character, will contain both that character and the null terminator. You have provided only a single character's worth of storage. So, the null terminator doesn't fit but it gets stored somewhere. As it happens, it's clobbering other data that happens to be next to opcion on the stack and that happens to be your ceros variable.
Declaring another variable has reorganized the layout of data on the stack and changes what gets clobbered, so you're not noticing it. It's still writing out of bounds, though.
You could use a format string of "%c" to read a single character.

Related

Output is printing twice, why?

The program is meant to remove the '-' from an ISBN code inputted, eg. "978-123456-789" is inputted and "978123456789" is outputted. Instead what I'm getting out is "978123456789978123456789" - it's printing it twice. Can someone please explain to me why? Thanks
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
int main(void)
{
char ISBN[16], arrayClean[12];
int i,j,k,a;
printf("Enter your ISBN: ");
scanf("%s",&ISBN);
for(i=0; i<=13; i++)
{
a = ISBN[i] - 48;
if(a==-3)
{
for(j=i;j<=13;j++)
{
k++;
ISBN[j]=ISBN[j+1];
}
k=0;
i=0;
}
}
for(i=0; i<=11; i++)
arrayClean[i]=ISBN[i];
printf("%s",arrayClean);
return 0;
}
You seem to have 12 chars in a number (excluding dashed. 14 counting them).
Your loops therefore cannot deal with chars 0 to 11 of the output, and chars 0 to 13 of the input. That is forgetting the terminal '\0' that needs to be there also, in the output, at position 12.
(If you are 100% sure there will be 12 chars, then you could solve this simply by adding arrayClean[12]=0 at the end, just before printing. But that would be a bad idea. Since it would be relying on what is typed by the user).
Also, even the declarations of your array "arrayClean" does not take into account the need for a terminal '\0'. You need 13 bytes to hold a 12 characters string.
Some other remarks:
Your usage of scanf("%s", &ISBN); is dangerous.
First of all, it should be scanf("%s", ISBN);. What you need to pass scanf is the address where to store what it reads. When you are reading a single int x;, then, indeed, you should scanf("%d", &x);, to have scanf store the result at the address where x is stored. But for a string, ISBN is already an address (the address of chars ISBN[0], ISBN[1], ...). So you should not pass the address of ISBN.
What saves you here, is that since ISBN is not a variable (it is an array, that is a constant pointer), in C &ISBN and ISBN are the same thing in this very context. So, it happens to work by accident.
But if ISBN were a variable (a char * allocated with malloc for example), then this usage would lead to memory errors. So, you should take the habit of not passing &ISBN to scanf but ISBN.
Other problem with that same line: when scaning, you cannot trust the user to type the exact number of bytes you expect them to. Here, if the user types 16 or more bytes, those byte will be written to whatever memory is after the 16 bytes of ISBN. Which will cause very serious problem. Even security ones if the user does this on purpose to overwrite other variables and even codes on some architecture.
So, rule of thumb: never ever scanf("%s", ...).
Always enforce a limit to the number of bytes scanf can read. scanf("%15s", ...) for example.
You are not null terminating the string. You are only copying 12 characters from ISBN to arrayClean. You need to add a null terminator to the end of arrayClean. You can do this by adding arrayClean[12] = '\0'; after the for loop.
char ISBN[16], arrayClean[12];
int i, j, k, a;
printf("Enter your ISBN: ");
scanf("%s", &ISBN);
for (i = 0; i <= 13; i++)
{
a = ISBN[i] - 48;
if (a == -3)
{
for (j = i; j <= 13; j++)
{
k++;
ISBN[j] = ISBN[j + 1];
}
k = 0;
i = 0;
}
}
for (i = 0; i <= 11; i++)
arrayClean[i] = ISBN[i];
arrayClean[12] = '\0';
printf("%s", arrayClean);

Searching for a character in an array by incrementing a pointer?

So the function I declared doesn't seem to working as intended, and even so, I don't think that's the proper way to compare characters by incrementing the pointer, so I'm generally lost here. To be honest, pointers have always confused me and I really need to learn how to use them if I am going to get better at C. Thanks anyone for any help!
Here's the code I have, and if this helps, the purpose of the program is for you to enter a line of text, enter a single character to search in that line of text, and then find those characters using CharIsAt. (Will add the following later) the values stored in "found" will then be printed as well.
#include <stdio.h>
#define SIZE 41
int CharIsAt(char *pStr,char ch,int loc[],int mLoc);
int main(void){
char array[SIZE],search;
int found[SIZE],chars;
printf("Enter a line of text(empty line to quit): ");
while (fgets(array,SIZE, stdin)!=NULL && array[0]!='\n')
{
printf("Enter a character to search: ");
search=getchar();
chars=CharIsAt(array,search,found,SIZE);
}
return 0;
}
int CharIsAt(char *pStr,char ch,int loc[],int mLoc){
//Searches for ch in *pStr by incrementing a pointer to access
//and compare each character in *pStr to ch.
int i,x;
for (i=0;i<mLoc;i++){
if (strcmp(pStr[i],ch)==0){
//Stores index of ch's location to loc
loc[i]=pStr[i];
x++;
}
}
//Returns the number of times ch was found
return x;
}
EDIT: Flipped sign around in the for loop. Now the program gives me a "stopped working" error.

C: Replacing a substring within a string using loops

I am struggling with the concept of replacing substrings within strings. This particular exercise does not want you to use built in functions from <string.h> or <strings.h>.
Given the string made up of two lines below:
"Mr. Fay, is this going to be a battle of wits?"
"If it is," was the indifferent retort, "you have come unarmed!"
I have to replace a substring with another string.
This is what I have so far, and I'm having trouble copying the substring to a new array, and replacing the substring with the new string:
#include <stdio.h>
#include <string.h>
int dynamic();
int main()
{
char str[]="\n\"Mr. Fay, is this going to be a battle of wits?\" \n\"If it is,\" was the indifferent retort, \"you have come unarmed!\"";
int i, j=0, k=0, l=0, n=0;
unsigned int e = n-2;
char data[150];
char newData[150];
char newStr[150];
printf("Give me a substring from the string");
gets(data);
printf("Give me a substring to replace it with");
gets(newData);
dynamic();
for (i=0; str[i] != '\0'; i++)
{
if (str[i] != data[j])
{
newStr[l] = str[i];
l++;
}
else if ((str[i+e] == data[j+e]) && (j<n))
{
newStr[l] = newData[j];
j++;
l++;
e--;
}
else if ((str[i+e] == data[j+e]) && (j>=n))
{
j++;
e--;
}
else
{
newStr[l] = str[i];
l++;
}
}
printf("original string is-");
for (k=0; k<n; k++)
printf("%c",str[k]);
printf("\n");
printf("modified string is-");
for(k=0; k<n; k++)
printf("%c",newStr[k]);
printf("\n");
}
int dynamic()
{
char str[]="\n\"Mr. Fay, is this going to be a battle of wits?\" \n\"If it is,\" was the indifferent retort, \"you have come unarmed!\"";
int i, n=0;
for (i=0; str[i] != '\0'; i++)
{
n++;
}
printf("the number of characters is %d\n",n);
return (n);
}
I tried your problem and got output for my code. Here is the code-
EDIT- THIS IS THE EDITED MAIN CODE
#include <stdio.h>
#include <string.h>
int var(char *); //function declaration. I am telling CPU that I will be using this function in the later stage with one argument of type char *
int main() //main function
{
char *str="\n\"Mr. Fay, is this going to be a battle of wits?\" \n\"If it is,\" was the indifferent retort, \"you have come unarmed!\"";
int i,j=0,k=0,l=0;
char data[] = "indifferent";
char newData[] = "nonchalant";
char newStr[150];
//here 'n' is returned from the 'var' function and is received in form of r,r1,r2,r3.
int r=var(str); //getting the length of str from the function 'var' and storing in 'r'
int r1=var(data); //getting the length of data from the function 'var' and storing in 'r1'
int r2=var(newData); //getting the length of newData from the function and storing in 'r2'
unsigned int e=r1-2; //r1-2 because r1 is the data to be replaced. and string index starts from 0. Here r1 is of length 12. but we dont need to check last
//character because it is null character and the index starts from 0. not from 1. so, it is 0 to 11 and 11th is '\0'. so "12-"2"=10" characters to be compared.
for(i=0;str[i]!='\0';i++)
{
if(str[i]!=data[j])
{
newStr[l]=str[i];
l++;
}
else if((str[i+e]==data[j+e]) && (j<r2))
{
newStr[l]=newData[j];
j++;
l++;
e--;
}
else if((str[i+e]==data[j+e]) && (j>=r2))
{
j++;
e--;
}
else
{
newStr[l]=str[i];
l++;
}
}
int r3=var(newStr); //getting the length of str from the function and storing in 'r'
printf("original string is-");
for(k=0;k<r;k++)
printf("%c",str[k]);
printf("\n");
printf("modified string is-");
for(k=0;k<r3;k++)
printf("%c",newStr[k]);
printf("\n");
} // end of main function
// Below is the new function called 'var' to get the character length
//'var' is the function name and it has one parameter. I am returning integer. so, it is int var.
int var(char *stri)//common function to get length of strings and substrings
{
int i,n=0;
for(i=0;stri[i]!='\0';i++)
{
n++; //n holds the length of a string.
}
// printf("the number of characters is %d\n",n);
return (n); //returning this 'n' wherever the function is called.
}
Let me explain few parts of the code-
I have used unsigned int e, because I don't want 'e' to go negative.(I will explain more about this later).
In the first for loop, I am checking whether my string has reached the end.
In first 'IF' condn, I am checking whether the first character of string is NOT-EQUAL to the first character of the word which needs to be replaced. If condition satisfies, print regularly thr original string.
ELSE IF, i.e(first character of string is EQUAL to the first character of the word)then check the next few characters to make sure that the word matches. Here, I used 'e' because it will check the condition for str[i+e] and data[i+e]. example- ai notequalto ae. If I had not used 'e'in code,... after checking the first character itself, newdata would have been printed in newstr. I used 'e'=5 because the probabilty of 1st letter and 5th letter being the same in data and the str is less. You can use 'e'=4 also. No rule that you have to use 'e'=5 only.
Now, I am decrementing 'e' and checking whether the letters in the string is same or no. I can't increment because, there is a certain limit of size of a string. As, I used unsigned int, 'e' won't go down below 0.
ELSE, (this means that only first letter is matching, the 5th letter of str and data are not matching), print the str in newstr.
In the last FOR loop, I have used k<114 because, that much characters are there in the string. (You can write a code to find how many characters are there in a string. No need to manually count).
And lastly, I have used conditions (j<10) and (j>=10) along with ELSE-IF condition because, in first ELSE-IF, the new data is ofsize 10. So, even if the word to be replaced is more than 10,say 12 for example. I don't need the extra 2 bits to be stored in new data. So, if the size is more than 10, just bypass that in the next ELSE-IF condition. Note that this 10 is the size of new word. So, it varies if your word is smaller or bigger. And , in second ELSE-IF, I am not incrementing 'l'(l++) because, here, I am not putting anything in newstr. I am just bypassing it. So, I didn't increment.
I tried my best to put the code in words. If you have any doubt, you can ask again. I will be glad to help. And this code is NOT OPTIMAL. The numerical values used varies with the words/strings you use. Ofcourse, I can write a generalized code for that(to fetch the numerical values automatically from the strings). But, I didn't write that code here. This code works for your problem. You can change few variables like 'e' and ELSE-IF part and try to understand how the code works. Play with it.
EDIT-
include
int main()
{
char str[]="\n\"Mr. Fay, is this going to be a battle of wits?\" \n\"If it is,\" was the indifferent retort, \"you have come unarmed!\"";// I took this as string. The string which u need to calculate the length, You have to pass that as the function parameter.
int i,n=0;
for(i=0;str[i]!='\0';i++)
{
n++;
}
printf("the number of characters is %d\n",n);
return (n);
}// If you execute this as a separate program, you will get the number of characters in the string. Basically, you just have to modify this code to act as a separate function and when calling the function, you have to pass correct arguments.
//Use Pointers in the function to pass arguments.

Validation of infinite input char \ number

I need to get a valid number from the user between 0-9 without duplicates.
The valid number can have any number of digit, from 1 to 10.
If the user type "space" or any kind of char, then the input is invalid.
My algorithm :
1) Create an array of char in size of 10, then initialize all cells to '0'.
2) For every char that reads from the user, check if the char actually between 0-9.
2.1) If true: count the respectively cell number +1.
2.2) Else "error".
2.3) If I get to a cell that already has +1, means this number already exist, then "error".
Now a few questions about my idea:
1) Is there any better\easy algorithm to do that?
2) The user doesn't type char by char, means I can get an infinite char length, so where do I store everything?
The answer to 2) is: you don't store the characters at all, you process them one by one. You only need storage to remember which digits you have already seen. I'd do it like this:
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char seen[10] = { 0 };
int c, loops;
for (loops = 0; (c = getchar()) != EOF && loops < 10; ++loops)
{
if (!isdigit(c)) {
printf ("Not a digit: %c\n", c);
break;
}
c -= '0';
if (seen[c]) {
printf ("Already seen: %d\n", c);
break;
}
seen[c] = 1;
}
return 0;
}
Try to modify this program as an exercise: reduce the storage requirements of the seen[] array. As written it uses one byte per digit. Make the program use only one bit per digit.

How do I read hex numbers into an unsigned int in C

I'm wanting to read hex numbers from a text file into an unsigned integer so that I can execute Machine instructions. It's just a simulation type thing that looks inside the text file and according to the values and its corresponding instruction outputs the new values in the registers.
For example, the instructions would be:
1RXY -> Save register R with value in
memory address XY
2RXY -> Save register R with value XY
BRXY -> Jump to register R if xy is
this and that etc..
ARXY -> AND register R with value at
memory address XY
The text file contains something like this each in a new line. (in hexidecimal)
120F
B007
290B
My problem is copying each individual instruction into an unsigned integer...how do I do this?
#include <stdio.h>
int main(){
FILE *f;
unsigned int num[80];
f=fopen("values.txt","r");
if (f==NULL){
printf("file doesnt exist?!");
}
int i=0;
while (fscanf(f,"%x",num[i]) != EOF){
fscanf(f,"%x",num[i]);
i++;
}
fclose(f);
printf("%x",num[0]);
}
You're on the right track. Here's the problems I saw:
You need to exit if fopen() return NULL - you're printing an error message but then continuing.
Your loop should terminate if i >= 80, so you don't read more integers than you have space for.
You need to pass the address of num[i], not the value, to fscanf.
You're calling fscanf() twice in the loop, which means you're throwing away half of your values without storing them.
Here's what it looks like with those issues fixed:
#include <stdio.h>
int main() {
FILE *f;
unsigned int num[80];
int i=0;
int rv;
int num_values;
f=fopen("values.txt","r");
if (f==NULL){
printf("file doesnt exist?!\n");
return 1;
}
while (i < 80) {
rv = fscanf(f, "%x", &num[i]);
if (rv != 1)
break;
i++;
}
fclose(f);
num_values = i;
if (i >= 80)
{
printf("Warning: Stopped reading input due to input too long.\n");
}
else if (rv != EOF)
{
printf("Warning: Stopped reading input due to bad value.\n");
}
else
{
printf("Reached end of input.\n");
}
printf("Successfully read %d values:\n", num_values);
for (i = 0; i < num_values; i++)
{
printf("\t%x\n", num[i]);
}
return 0
}
You can also use the function strtol(). If you use a base of 16 it will convert your hex string value to an int/long.
errno = 0;
my_int = strtol(my_str, NULL, 16);
/* check errno */
Edit: One other note, various static analysis tools may flag things like atoi() and scanf() as unsafe. atoi is obsolete due to the fact that it does not check for errors like strtol() does. scanf() on the other hand can do a buffer overflow of sorts since its not checking the type sent into scanf(). For instance you could give a pointer to a short to scanf where the read value is actually a long....and boom.
You're reading two numbers into each element of your array (so you lose half of them as you overwrite them. Try using just
while (i < 80 && fscanf(f,"%x",&num[i]) != EOF)
i++;
for your loop
edit
you're also missing the '&' to get the address of the array element, so you're passing a random garbage pointer to scanf and probably crashing. The -Wall option is your friend.
In this case, all of your input is upper case hex while you are trying to read lower case hex.
To fix it, change %x to %X.
Do you want each of the lines (each 4 characters long) separated in 4 different array elements? If you do, I'd try this:
/* read the line */
/* fgets(buf, ...) */
/* check it's correct, mind the '\n' */
/* ... strlen ... isxdigit ... */
/* put each separate input digit in a separate array member */
num[i++] = convert_xdigit_to_int(buf[j++]);
Where the function convert_xdigit_to_int() simply converts '0' (the character) to 0 (an int), '1' to 1, '2' to 2, ... '9' to 9, 'a' or 'A' to 10, ...
Of course that pseudo-code is inside a loop that executes until the file runs out or the array gets filled. Maybe putting the fgets() as the condition for a while(...)
while(/*there is space in the array && */ fgets(...)) {
}

Resources