convert a character value to integer value - c

here when ever i find 'h' i have to access the values between p and h i.e 123 and i want that has int and store it in value as 123 itself how can i do this can any one tell me the logic, that code that i have written is not working and how to copy the values when the pointer is getting incremented
main()
{
char *ptr1 = "p123h12";
int value;
while(*ptr1!= '\0')
{
if(*ptr1 == 'h')
{
value = (int)atoi(ptr1);
printf("%d\n", value);
}
ptr1++;
}
}

With sscanf:
int value;
sscanf (ptr1,"p%dh12",&value);
Update
int i,j;
int values[MAX_VALUES];
int startIdx = -1;
char *ptr1 = "p123hxxxxp124hxxxxp123145hxxxx";
char buffer[16];
for(i=0,j=0; i<strlen(ptr1);i++)
{
if(startIdx>=0 && ptr[i] == 'h')
{
strncpy(buffer,ptr1+startIdx,i-startIdx+1);
buffer[i-startIdx+1]='\0';
sscanf (buffer,"p%dh",&(values[j++]));
startIdx = -1;
}
else if(ptr[i] == 'p')
{
startIdx = i;
}
}

Here's a good possible starting point:
#include <stdio.h>
#include <ctype.h>
int main (void) {
char *p, *str = "p123h12p97h62p32h";
int accum = 0;
// Process every character.
for (p = str; *p != '\0'; p++) {
// 'p' resets the accumulator.
// 'h' outputs the accumulator.
// Any digit adjusts the accumulator.
if (*p == 'p') accum = 0;
if (*p == 'h') printf ("Processing %d\n", accum);
if (isdigit (*p)) accum = accum * 10 + *p - '0';
}
return 0;
}
This will work fine if your input string follows your specified format, outputting:
Processing 123
Processing 97
Processing 32
If there's the possibility that your input string is not so well formed, you'll need to add some defensive coding.

Related

How to make the calculator count the expression with spaces in the input?

I tried to make calculator supporting brackets, but
I have no idea how to deal if the user's input includes expression with spaces, for example:
input: (2 + 3) * 2
i got: 2
If it's normally get (2+3)*2, it counts 10
.
My code:
#include <stdio.h>
#define MAX_SIZE 1024
int insert_operand(int *operand, int * top_num, int num) /* data is pushed into the data stack*/
{
(*top_num) ++;
operand[*top_num] = num; /*save data*/
return 0; /*Exit normally*/
}
int insert_oper (char * oper , int *top_oper , char ch)
{
(*top_oper)++;
oper[*top_oper] = ch; /*save operator*/
return 0; /*Exit normally*/
}
int compare(char *oper , int *top_oper , char ch) /* compare the priority of the operating server*/
{
if((oper[*top_oper] == '-' || oper[*top_oper] == '+') /*Determine whether the current priority is higher than the priority of the operator at the top of the stack*/
&& (ch == '*' || ch == '/'))
{
return 0;
}
else if(*top_oper == -1 || ch == '('
|| (oper[*top_oper] == '(' && ch != ')')) /*Determine whether the operator stack is empty; whether the top operator is '('*/
{
return 0;
}
else if (oper[*top_oper] =='(' && ch == ')')
{
(*top_oper)--;
return 1;
}
else
{
return -1; /*Operate the operator*/
}
}
int deal_date(int *operand ,char *oper ,int *top_num, int *top_oper) /*perform data operation*/
{
int num_1 = operand[*top_num]; /*Take out two data from the data stack*/
int num_2 = operand[*top_num - 1];
int value = 0;
if(oper[*top_oper] == '+')
{
value = num_1 + num_2;
}
else if(oper[*top_oper] == '-')
{
value = num_2 - num_1;
}
else if(oper[*top_oper] == '*')
{
value = num_2 * num_1;
}
else if(oper[*top_oper] == '/')
{
value = num_2 / num_1;
}
(*top_num) --; /*Move the top of the data stack down one bit*/
operand[*top_num] = value; /*Push the obtained value into the data stack*/
(*top_oper) --; /*Move the top of the operator stack down one bit*/
}
int main()
{
int operand[MAX_SIZE] = {0}; /*data stack, initialize*/
int top_num = -1;
char oper[MAX_SIZE] = {0}; /*operator stack, initialize*/
int top_oper = -1;
char *str = (char *) malloc (sizeof(char) * 100); /*get expression (without =)*/
scanf("%s", str);
char* temp;
char dest[MAX_SIZE];
int num = 0;
int i = 0;
while(*str != '\0')
{
temp = dest;
while(*str >= '0' && *str <= '9') /*judging whether it is data*/
{
*temp = *str;
str++;
temp++;
} /*Encounter a symbol to exit*/
if(*str != '(' && *(temp - 1) != '\0') /*Determine whether the symbol is '('*/
{
*temp = '\0';
num = atoi(dest); /*convert string to number*/
insert_operand(operand, &top_num,num); /*Push data into the data stack*/
}
while(1)
{
i = compare(oper,&top_oper,*str); /*judgment operator priority*/
if(i == 0)
{
insert_oper(oper,&top_oper,*str); /*press operator*/
break;
}
else if(i == 1) /*judging whether the expression in brackets ends*/
{
str++;
}
else if(i == -1) /* data processing */
{
deal_date(operand,oper,&top_num,&top_oper);
}
}
`
str ++; /* point to the next character of the expression */
}
`
printf("%d\n",operand[0]); /*output result*/
return 0;
I tried to count the equation even if there is a space in it. Can someone please help?
Solving the problem by removing spaces:
So if you're working with equation as string you can simply remove spaces with function like this (there will be probably better way or function in library string.h but this was first guess):
char* DeleteSpaces( char* stringWithSpaces, size_t lengthOfString)
{
char* stringWithoutSpaces = (char*)calloc(lengthOfString + 1, sizeof(char));
if( !stringWithoutSpaces )
return NULL;
for( unsigned int x = 0, y = 0; x <= lengthOfString; x++, y++ )
{
if( stringWithSpaces[x] == ' ' ) // if the character is space
{
while( stringWithSpaces[x] == ' ' && x < lengthOfString ) // skip all the spaces OR go away before you hit '\0'
x++;
stringWithoutSpaces[y] = stringWithSpaces[x]; // then copy next character into new string
}
else // if there's no space just copy the character
stringWithoutSpaces[y] = stringWithSpaces[x];
}
return stringWithoutSpaces;
}
This will basically remove all spaces from your received equation. If you really need the smallest possible memory requirement you can use realloc() at the end of the function for more optimal memory usage.
Here's simple example of how to use the function so you can test it:
int main()
{
char firstString[] = "H e l l o w o r l d\0";
char* secondString;
secondString = DeleteSpaces( firstString, strlen(firstString) );
if( !secondString )
return -1;
printf( "%s", secondString );
free( secondString );
return 0;
}
Don't forget to use free(SecondString). I hope I helped you atleast a little :)
As with the previous answer, I added in a function to remove any spaces from the entered formula in order to process the requested calculation. Also, coupled with that, I revised the "scanf" input to read in all of the entered characters which looked to be another symptom you were facing. With that, following is a refactored version of your program with the additional space compression function.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 1024
int insert_operand(int *operand, int * top_num, int num) /* data is pushed into the data stack*/
{
(*top_num) ++;
operand[*top_num] = num; /*save data*/
return 0; /*Exit normally*/
}
int insert_oper (char * oper , int *top_oper , char ch)
{
(*top_oper)++;
oper[*top_oper] = ch; /*save operator*/
return 0; /*Exit normally*/
}
int compare(char *oper , int *top_oper , char ch) /* compare the priority of the operating server*/
{
if((oper[*top_oper] == '-' || oper[*top_oper] == '+') /*Determine whether the current priority is higher than the priority of the operator at the top of the stack*/
&& (ch == '*' || ch == '/'))
{
return 0;
}
else if(*top_oper == -1 || ch == '('
|| (oper[*top_oper] == '(' && ch != ')')) /*Determine whether the operator stack is empty; whether the top operator is '('*/
{
return 0;
}
else if (oper[*top_oper] =='(' && ch == ')')
{
(*top_oper)--;
return 1;
}
else
{
return -1; /*Operate the operator*/
}
}
int deal_date(int *operand ,char *oper ,int *top_num, int *top_oper) /*perform data operation*/
{
int num_1 = operand[*top_num]; /*Take out two data from the data stack*/
int num_2 = operand[*top_num - 1];
int value = 0;
if(oper[*top_oper] == '+')
{
value = num_1 + num_2;
}
else if(oper[*top_oper] == '-')
{
value = num_2 - num_1;
}
else if(oper[*top_oper] == '*')
{
value = num_2 * num_1;
}
else if(oper[*top_oper] == '/')
{
value = num_2 / num_1;
}
(*top_num) --; /*Move the top of the data stack down one bit*/
operand[*top_num] = value; /*Push the obtained value into the data stack*/
(*top_oper) --; /*Move the top of the operator stack down one bit*/
return value;
}
void compress(char *stx) /* The additional function */
{
char work[101];
int i = strlen(stx);
strcpy(work, stx);
for (int j = 0; j < i; j++)
{
stx[j] = 0;
}
i = 0;
for (int j = 0; j < (int)strlen(work); j++)
{
if (work[j] != ' ')
{
stx[i] = work[j];
i++;
}
}
}
int main()
{
int operand[MAX_SIZE] = {0}; /*data stack, initialize*/
int top_num = -1;
char oper[MAX_SIZE] = {0}; /*operator stack, initialize*/
int top_oper = -1;
char *str = (char *) malloc (sizeof(char) * 100); /*get expression (without =)*/
//scanf("%s", str);
scanf("%[^\n]", str); /* Refined the scanf call to receive all characters prior to the newline/return character */
compress(str); /* Added this function to remove spaces */
char* temp;
char dest[MAX_SIZE];
int num = 0;
int i = 0;
while(*str != '\0')
{
temp = dest;
while(*str >= '0' && *str <= '9') /*judging whether it is data*/
{
*temp = *str;
str++;
temp++;
} /*Encounter a symbol to exit*/
if(*str != '(' && *(temp - 1) != '\0') /*Determine whether the symbol is '('*/
{
*temp = '\0';
num = atoi(dest); /*convert string to number*/
insert_operand(operand, &top_num,num); /*Push data into the data stack*/
}
while(1)
{
i = compare(oper,&top_oper,*str); /*judgment operator priority*/
if(i == 0)
{
insert_oper(oper,&top_oper,*str); /*press operator*/
break;
}
else if(i == 1) /*judging whether the expression in brackets ends*/
{
str++;
}
else if(i == -1) /* data processing */
{
deal_date(operand,oper,&top_num,&top_oper);
}
}
str ++; /* point to the next character of the expression */
}
printf("%d\n",operand[0]); /*output result*/
return 0;
}
Testing out your sample formula with some additional spacing to ensure the compression function was working properly, following was the terminal output.
#Vera:~/C_Programs/Console/Calculate/bin/Release$ ./Calculate
(2 + 3) * 2
10
Give that a try and see if it meets the spirit of your project.
As pointed out in the comments and other answers, the solution may be to simply "compact" the spaces out of the string before trying to analyse the string's content.
This doesn't require a lot of code:
#include <stdio.h>
char *stripSP( char *src ) {
for( char *d = src, *s = src; ( *d = *s ) != '\0'; s++ )
d += *d != ' ';
return src;
}
int main( void ) {
char *s[] = { "Hello", "H e l l ooo", "(2 + 5) * 3" };
for( int i = 0; i < 3; i++ ) {
printf( "From '%s' ", s[i] );
printf( "'%s'\n", stripSP( s[i] ) );
}
return 0;
}
From 'Hello' 'Hello'
From 'H e l l ooo' 'Hellooo'
From '(2 + 5) * 3' '(2+5)*3'
Even more compact would be to use array indexing:
char *stripSP( char s[] ) {
for( int f=0, t=0; (s[t] = s[f++]) != '\0'; t += s[t] != ' ' ) {}
return s;
}

How do I remove duplicate vowels from a string?

Question: Define an int function that removes all consecutive vowel repetitions from a string. The function should return the number of vowels removed and present the string without duplicates.
I am PT so Vogais is Vowels; Digite uma String is Write one String. A String sem duplicados fica assim ' %s ' e foram retiradas %d vogais is The string without duplicates is ' %s ' and where removed %d vowels.
Explanation: In portuguese we have some words with two consecutive vowels like: coordenador, coordenação (chqrlie example). But in thouse cases should be ignored in the context of this problem.
Problem: When I test a string like 'ooooo' it says the string without duplicate vogals is 'oo' and where removed 3 vowels. But it should be 'o' and 4 vowels removed. Another example with error is 'Estaa e umaa string coom duuuplicadoos', I am getting ' Esta e uma string com duplcdos ' and 8 vowels removed.
Note: This is a simple question so there isn't need to complicate. It only askes the consecutive duplicate vowels. The cases 'oOoO' -> 'oO' ,'abAb'->'abAb','abab' -> 'ab','aba'-> 'aba',... are in another chapter XD.
int Vogais(char *s) {
if (*s == 'A' || *s == 'a' || *s == 'E' || *s == 'e'
|| *s == 'I' || *s == 'i' || *s == 'O' || *s == 'o'
|| *s == 'U' || *s == 'u') return 1;
return 0;
}
int retiraVogaisRep(char *s) {
int res = 0;
for (int i = 0; i < strlen(s); i++) {
for (int j = i + 1; s[j] != '\0'; j++) {
if (s[i] == s[j] && Vogais(&s[j]) == 1) {
res++;
for (int k = j; s[k] != '\0'; k++) {
s[k] = s[k + 1];
}
}
}
}
return res;
}
int main() {
char s[38];
printf("Digite uma String:\n");
scanf("%[^\n]", s);
int res = retiraVogaisRep(s);
printf("A String sem duplicados fica assim ' %s ' e foram retiradas %d vogais.\n", s, res);
return 0;
}
Your code is too complicated: there is no need for nested loops for this task and you do not set the null terminator when shortening the string.
Here is a simpler version:
#include <stdio.h>
#include <string.h>
int retiraVogaisRep(char *s) {
int i, j; // use 2 running indices
char c, last = 0;
for (i = j = 0; (c = s[i]) != '\0'; i++) {
if (c != last || !strchr("aeiouAEIOU", c))
s[j++] = last = c;
}
s[j] = '\0'; // set the null terminator
return i - j; // return the number of bytes removed
}
int main() {
char s[100];
printf("Digite uma String:\n");
// read the user input safely with `fgets()`
if (!fgets(s, sizeof s, stdin))
return 1;
// strip the trailing newline if any
s[strcspn(s, "\n")] = '\0';
// remove duplicate consecutive vowels
int res = retiraVogaisRep(s);
printf("A String sem duplicados fica assim ' %s ' e foram retiradas %d vogais.\n", s, res);
return 0;
}
The question tag is C, but I will not post the actual code here.
The pseudocode:
function is_vowel(int c) {...}
start loop c = <src>
if next_char is past the last char then quit loop;
if is_vowel(c) and c == next_char and is_vowel(next_char)
then continue;
else
copy c to <dst>
You should elaborate on this, as the above is possibly having small issues. Nevertheless, I think this answer is somewhat shorter and gives an insight.
Update
The above is definitly have an issue, in that the next char does not copied to the output. The mistake is easy to correct, so I will leave it up to OP.
Update
Edited above code to indicate that OP wants to remove only identical duplicates. So, the case of a charcter is important.
Rather than a triple nested loop, consider a single walk down the string, looking for repeats.
#include <stdio.h>
#include <ctype.h>
int Vogais(unsigned char s) {
if (s == 'A' || s == 'a' || s == 'E' || s == 'e'
|| s == 'I' || s == 'i' || s == 'O' || s == 'o'
|| s == 'U' || s == 'u') return 1;
return 0;
}
int retiraVogaisRep(char *s) {
unsigned char *us = (unsigned char *) s;
unsigned char *dest = us;
int res = 0;
int prior = EOF;
while (*us) {
while (toupper(*us) == prior) {
us++;
res++;
}
prior = Vogais(*us) ? toupper(*us) : EOF;
*dest++ = *us++;
}
*dest = '\0';
return res;
}
int main() {
char buf[100] = "OoFreedaa";
printf("%d\t", retiraVogaisRep(buf));
printf("<%s>\n", buf);
return 0;
}
Output
3 <OFreda>
Remove consecutive duplicate vowels
You should use tolower function from ctype.h to check for vowels, that include the letter 'y', see below working code:
You can store previous character in prev and compare it to the current character, as you are case insensitive you store the tolower version.
#include <string.h>
#include <stdio.h>
#include <ctype.h>
int Vogais(char c){
return (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' || c == 'y') ;
}
int retiraVogaisRep (unsigned char *s){
if (*s == NULL)
return 0;
unsigned char t[256];
memset(t, 0, sizeof(t));
int res = 0;
int j = 0;
t[0] = s[0];
char prev = tolower(s[0]);
int len = strlen(s);
for (int i = 1; i < len; i++) {
char c = tolower(s[i]);
if (Vogais(c) && c == prev)
++res;
else
t[j++] = s[i];
prev = c;
}
memcpy(s, t, sizeof(t));
return res;
}
int main(){
char s[256];
printf("Digite uma String:\n");
scanf("%255[^\n]", s);
int res = retiraVogaisRep(s);
printf("Da String ' %s ' podem ser retiradas %d vogais.\n", s,res);
return 0;
}
Retaining the uppercase, using the Kernighan-copy
#include <stdio.h>
#include <string.h>
#include <ctype.h>
size_t remove_duplicate_vowels(char *str)
{
int old,new;
size_t dst,src;
old = 0;
for(dst=src=0; str[dst] = str[src]; old=new, src++ ) {
new = toupper( str[dst] );
if ( !strchr( "AEIOU", new )) { // Not a vowel
dst++; continue;
}
if ( new != old ) { // Not a repetition
dst++; continue;
}
}
return src - dst;
}
int main(int argc, char **argv)
{
char test[] = "Aaa bbBb CccCC d eEeee!";
char *arg;
size_t ret;
arg = argv[1] ? argv[1] : test;
ret = remove_duplicate_vowels(arg);
fprintf(stderr, "[%zu]: %s\n", ret, arg);
return 0;
}

C parser program to add list of numbers separated by ; over multiple lines taking input using read()

I want to write a program that takes numbers as inputs over multiple lines that are identified/separated by let's say ; character and print out their sum(s). Example:
1 2 3; 4 5 6; 7 8 9;(enter)
10 11 12;(enter)
exit(enter)
And I want the expected output to be exactly like:
List 1: 6 (sum of 1 2 3)
List 2: 15 (sum of 4 5 6)
List 3: 24 (sum of 7 8 9)
List 4: 33 (sum of 10 11 12)
sum of a b c, printing out this is not necessary, but their result as number is (enter), i.e. I'm pressing enter/getting to new line.
I am terminating when user types exit. But I am getting segmentation fault error in my code. Plus in this code the sum is also getting wrong values (I tried it separately).
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main() {
char *b;
int sum = 0;
int rc;
int i = 1;
while (strcasecmp(b, "exit") != 0) {
char buff[50];
rc = read(0, buff, 50);
if (rc == -1) {
perror("");
exit(0);
}
char *a = buff;
b = strtok(a, "\n");
char *c = strtok(b, ";");
while (c != NULL) {
char *d = strtok(c, " ");
while (d != NULL) {
int a = atoi(d);
sum += a;
d = strtok(NULL, " ");
printf("List %d: %d", i, sum);
i++;
}
c = strtok(NULL, ";");
}
}
}
You can use getchar and parse the integers on the go as below, without strtok.
int main() {
int sum = 0; int rc; int i = 0, j = 0;
char buff[50] = "";
while(1) {
if (i>= sizeof buff) break; //not enough memory
if (read(STDIN_FILENO, &buff[i], 1) < 1) {break;} //read error
if (strcasecmp(buff, "exit") == 0) break;
else if (buff[i] == ';'){
buff[i] = '\0';
int a = atoi(buff);
sum += a;
printf("sum = %d\n", sum);
sum = 0;
i = 0;
memset(buff, 0 , sizeof buff);
}
else if (buff[i] == ' '){
buff[i] = '\0';
int a = atoi(buff);
sum += a;
i = 0;
}
else if (buff[i] != '\n'){
i++;
}
}
}
There are multiple problems in your code:
b is an uninitialized pointer, reading and writing through it have undefined behavior, most likely the cause of the segmentation fault.
you should not use the POSIX low level functions to read input, it is non portable and the input might not be read in line chunks and will not be null terminated... Furthermore, a -1 return value is not always an error.
Use fgets() or other standard stream functions.
Here is a simple solution if you can assume that lists do not span multiple lines and are always terminated by ;:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int sumlist(int n, char *str) {
char *p, *q;
int sum = 0, term;
for (p = str;; p = q) {
p += strspn(p, " \t\n"); // skip blanks
if (*p == '\0')
break;
term = strtol(p, &q, 10);
if (q == p) {
printf("invalid input: %s\n", str);
return -1;
}
sum += term;
}
printf("List %d: %d (sum of %s)\n", n, sum, str);
return 0;
}
int main() {
char buf[200];
int n = 1;
char *p, *q;
while (fgets(buf, sizeof buf, stdin) {
for (p = str;;) {
p += strspn(p, " \t\n"); // skip initial blanks
if (*p == '\0')
break;
q = strchr(p, ';');
if (q != NULL)
*q = '\0';
if (p == q) {
p = q + 1; // skip empty lists
continue;
}
if (!strcmp(p, "exit"))
break;
sumlist(n++, p);
if (q == NULL)
break;
p = q + 1;
}
}
return 0;
}
If you cannot use fgets() or any standard stream functions, re-write your own version, reading one byte at a time from the OS handle with read() and carefully test for potential signal interrupts:
#include <errno.h>
#include <unistd.h>
char *my_gets(int hd, char *buf, size_t size) {
size_t i;
for (i = 0; i + 1 < size;) {
ssize_t n = read(hd, &buf[i], 1);
if (n != 1) {
if (n == -1 && errno == EINTR)
continue;
break;
}
if (buf[i++] == '\n')
break;
}
if (i == 0)
return NULL;
buf[i] = '\0';
return buf;
}
int main() {
char buf[200];
int n = 1;
char *p, *q;
while (my_gets(0, buf, sizeof buf) {
for (p = str;;) {
p += strspn(p, " \t\n"); // skip initial blanks
if (*p == '\0')
break;
q = strchr(p, ';');
if (q != NULL)
*q = '\0';
if (p == q) {
p = q + 1; // skip empty lists
continue;
}
if (!strcmp(p, "exit"))
break;
sumlist(n++, p);
if (q == NULL)
break;
p = q + 1;
}
}
return 0;
}
There are already working solutions here, but I'd like to suggest another one that might be helpful to understand some concepts.
Although you cannot use getc and ungetc, I would still address your problem in a way that uses the concept of a get_buf. My solution reads a character at a time and tries to turn it into a valid token that the main loop can switch on. In my opinion, that's a nice way to handle the parsing of simple 'languages' like the one you want to interpret. Also, it is pretty extensible & it's easy to add additional tokens (e.g. math operations like + - / *).
As a quick description what's happening: In get_char, a single byte is read from STDIN whenever the internal buffer is empty. If it is not, the character that's on the buffer is returned. This functionality is used by get_valid_token which returns either your delimiter ; or a (potentially multi-digit) number. Being able to 'unget' a character is required here. In main, we continuously get tokens and perform the appropriate action, nicely separating getting and interpretation of tokens. Obviously, this a quick and dirty program, but it might work for you.
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BUF_SIZ 2 /* get_buf never buffers more than one char by design */
static char get_buf[BUF_SIZ];
static char *get_buf_ptr = get_buf;
char get_char(int fd)
{
char c;
/* check buffer first */
if (!(get_buf == get_buf_ptr))
return *get_buf_ptr--;
/* if buffer is empty, read from STDIN */
if ((read(fd, &c, 1)) == -1) {
perror("read");
exit(1);
}
return c;
}
void unget_char(char c)
{
*(++get_buf_ptr) = c;
}
void flush(int fd)
{
char c;
do {
read(fd, &c, 1);
} while (c != '\n');
}
char is_exit()
{
if ((get_char(STDIN_FILENO)) != 'x') return 0;
if ((get_char(STDIN_FILENO)) != 'i') return 0;
if ((get_char(STDIN_FILENO)) != 't') return 0;
flush(STDIN_FILENO); /* remove already buffered input */
return 1;
}
char *get_valid_token(void)
{
char c;
char *out;
char *out_ptr;
out_ptr = out = (char *)malloc(sizeof(char)*BUFSIZ);
while (1) {
c = get_char(STDIN_FILENO);
if (c == ';') {
*out = ';';
break;
} else if (isdigit(c)) {
*out = c;
out_ptr++;
/* get the rest of the digit */
while (1) {
c = get_char(STDIN_FILENO);
if (isdigit(c)) {
*out_ptr++ = c;
} else {
unget_char(c);
break;
}
}
*out_ptr = '\0';
break;
} else if (c == 'e') {
if (is_exit())
exit(0);
}
};
return out;
}
int main(void)
{
char *t;
int sum;
sum = 0;
while ((t = get_valid_token())) {
switch (*t) {
case ';':
fprintf(stderr, "sum: %d\n", sum);
sum = 0;
break;
default:
sum += atoi(t);
break;
}
free(t);
}
return 0;
}

Writing my own atoi function

I am trying to convert a string of numerical characters to their corresponding integral form. Please suggest what is wrong with the code. I would like to stick with pointers. I understand that the pointer str points to the first character in my string. So, each time I call my function in the loop, I want the pointer to increment by 1, and add the value of the character to one node in my array. For some reason, though I am unable to do so. Here is the code.
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
int ctoi(char *c);
int main (void)
{
char *str;
int A[20];
int i = 0;
str = (char*) malloc(20 * sizeof(char));
printf("Input the string. ");
scanf("%s", str);
while(str != '\0')
{
A[i] = ctoi(str);
i++;
str++;
}
for(i = 0; i < strlen(str); i++)
printf("%d", A[i]);
getchar();
getchar();
return 0;
}
int ctoi(char *c)
{
int a;
a= *c - '0';
return a;
}
for (i=0;i<strlen(str);i++)
printf("%d", A[i]);
Here strlen will return 0 because you updated str in your previous loop .Replace it with :
for(i=0;i<len;i++)
where len is the length of your input string .Find it before using str in while loop
while(str!='\0') should be `while(*str!='\0')`
. You will get it . But for writing your own atoi function you dont need to store the number in an array
Please try this it works, the myatoi() function was lifted perhaps 20 years ago from the classic "THE C PROGRAMMING LANGUAGE" , get the book.
#include <stdio.h>
main()
{
char temp[99];
strcpy(temp , "34");
printf( "\n %d " , myatoi(temp));
strcpy( temp , "8642");
printf( "\n %d " , myatoi(temp));
}
int myatoi( char s[])
{
int i,n,sign;
// skip white space
for( i=0 ; s[i]==' ' || s[i]=='\n' ||s[i]=='\t';i++) ;
sign=1;
if( s[i]=='+' || s[i]=='-')
sign=( s[i++]=='+' ? 1 : -1 );
for( n=0; s[i]>='0' && s[i]<='9' ; i++)
n=10*n+s[i]-'0' ;
return(sign*n);
}
OP's code needs a few (at least 2) fixes to mostly work. See ***
int main (void)
{
char *str;
int A[20];
int i = 0;
// *** Cast not needed, '* sizeof(char)' not needed
str = malloc(20);
printf("Input the string. ");
scanf("%s", str);
// ***
char *str_original = str;
while(*str != '\0')
{
A[i] = ctoi(str);
i++;
str++;
}
// ***
str = str_original;
for(i = 0; i < strlen(str); i++)
printf("%d", A[i]);
// ***
free(str); // Good to return memory
str = NULL;
getchar();
getchar();
return 0;
}
A simple way to convert a string to an int
int strtoi(const char *s) {
int sum = 0;
char ch;
char sign = *s;
if (*s == '-' || *s == '+') s++;
while ((ch = *s++) >= '0' && ch <= '9') {
sum = sum * 10 - (ch - '0');
}
if (sign != '-') {
sum = -sum;
}
return sum;
}
Notes: This code accumulates the sum on the negative side of 0 to avoid UB when trying to parse the string for INT_MIN. Modified code could skip leading white-space, add text error detection, overflow detection, etc.
Here is my custom atoi funtion, who handle unsigned int with debug gestion:
int my_getnbr(char *str)
{
int nb;
int sign;
int i;
nb = 0;
sign = 0;
i = -1;
if (!str)
return (0);
while (str[++i])
if (str[i] < '0' && str[i] > '9' && str[i] != '-' && str[i] != '+')
return (0);
i = 0;
while (str[i] != '\0' && (str[i] == '-' || str[i] == '+'))
if (str[i++] == '-')
++sign;
while (str[i] && (str[i] >= '0' && str[i] <= '9'))
{
nb = (nb * 10) + (str[i++] - '0');
if (str[i] == ' ')
i++;
}
return (((sign % 2) == 1) ? ((nb) * (-1)) : (nb));
}
tested with that main:
int main()
{
printf("%d\n", my_getnbr("-42"));
printf("%d\n", my_getnbr("-+-+--42"));
printf("%d\n", my_getnbr("-0"));
printf("%d\n", my_getnbr("590310"));
return (0);
}
No leaks, here is the result:
-42
42
0
590310
Firstly
while(str!='\0') should be
while(*str!='\0')
You should compare the content, not the address.
And while printing the returned data, you are doing
for(i=0;i<strlen(str);i++)
printf("%d", A[i]);
str already parsed till the last. So length would probably be 0.
Change your while loop to
while(*str!='\0')
{
A[i]=ctoi(*str);
i++;
str++;
}
And your function to
int ctoi(char c)
{
int a;
a= c-'0';
return a;
}
There are several approaches for a simple atoi replacement without the base conversion flexibility in strtol. The simplest is generally to find the length of the string to convert, and then work backward toward the front of the string preforming the conversion from string to integer as you go. A quick example would be:
/* a quick atoi replacement */
int atoi2 (char *s)
{
int nmax = (1ULL << 31) - 1; /* INT_MAX */
long long n = 0; /* the number to return */
size_t m = 1; /* multiplier for place */
size_t l = 0; /* length of string */
char *p = s;
while (*p++) l++; /* get string length */
p -= 2; /* position at last char */
while (l--) /* for each char in string */
{ /* verify a digit or '-' sign */
if ((*p >= '0' && *p <= '9') || *p == '-')
{
if (*p == '-') { /* if '-' is first char */
if (p == s) n = -n; /* negate value */
}
else { /* otherwise normal conversion */
n += (*p - '0') * m;
if (n > nmax) { /* prevent overflow */
fprintf (stderr, "atoi2() error: conversion > INT_MAX.\n");
exit (EXIT_FAILURE);
}
m *= 10;
}
}
p--;
}
return (int) n;
}
A simple driver program to test could be:
#include <stdio.h>
#include <stdlib.h>
int atoi2 (char *s);
int main (int argc, char **argv) {
if (argc < 1) return 1;
printf ("\n string : %s, conversion : %d\n\n",
argv[1], atoi2 (argv[1]));
return 0;
}
Example Use/Output
$ ./bin/atoi2 321
string : 321, conversion : 321
$ ./bin/atoi2 -321
string : -321, conversion : -321
$ ./bin/atoi2 2147483647
string : 2147483647, conversion : 2147483647
$ ./bin/atoi2 2147483648
atoi2() error: conversion > INT_MAX.
If you have any questions, please do not hesitate to ask.
Here is a custom atoi function that avoids using most of the standard library functions
/*** _atoi - finds the first set of integers in a given string
* #s: string entered
* Return: first number sequence
**/
int _atoi(char *s)
{
int length = 0, negativeCount = 0, count = 0, num = 0;
while (s[length] != '\0')
{
length++;
}
while (count < length)
{
if (s[count] == '-')
{
negativeCount++;
}
if (s[count] >= 48 && s[count] <= 57)
{
/* ascii values for numbers */
for (; s[count] >= 48 && s[count] <= 57; count++)
{
num = (10 * num - (s[count] - 48));
}
break;
}
count++;
}
if (negativeCount % 2 != 0)
{
return (num);
}
else
{
return (-num);
}
}

C program to remove repeated char from a string

I came across a interview question that asked to remove the repeated char from a given string, in-place.
So if the input was "hi there" the output expected was "hi ter". It was also told to consider only alphabetic repititions and all the
alphabets were lower case. I came up with the following program. I have comments to make my logic clear. But the program does not work as expectd for some inputs. If the input is "hii" it works, but if its "hi there" it fails. Please help.
#include <stdio.h>
int main()
{
char str[] = "programming is really cool"; // original string.
char hash[26] = {0}; // hash table.
int i,j; // loop counter.
// iterate through the input string char by char.
for(i=0,j=0;str[i];)
{
// if the char is not hashed.
if(!hash[str[i] - 'a'])
{
// hash it.
hash[str[i] - 'a'] = 1;
// copy the char at index i to index j.
str[j++] = str[i++];
}
else
{
// move to next char of the original string.
// do not increment j, so that later we can over-write the repeated char.
i++;
}
}
// add a null char.
str[j] = 0;
// print it.
printf("%s\n",str); // "progamin s ely c" expected.
return 0;
}
when str[i] is a non-alphabet, say a space and when you do:
hash[str[i] - 'a']
your program can blow.
ASCII value of space is 32 and that of a is 97 so you are effectively accessing array hash with a negative index.
To solve this you can ignore non-alphabets by doing :
if(! isalpha(str[i]) {
str[j++] = str[i++]; // copy the char.
continue; // ignore rest of the loop.
}
This is going to break on any space characters (or anything else outside the range 'a'..'z') because you are accessing beyond the bounds of your hash array.
void striprepeatedchars(char *str)
{
int seen[UCHAR_MAX + 1];
char *c, *n;
memset(seen, 0, sizeof(seen));
c = n = str;
while (*n != '\0') {
if (!isalpha(*n) || !seen[(unsigned char) *n]) {
*c = *n;
seen[(unsigned char) *n]++;
c++;
}
n++;
}
*c = '\0';
}
This is code golf, right?
d(s){char*i=s,*o=s;for(;*i;++i)!memchr(s,*i,o-s)?*o++=*i:0;*o=0;}
...
// iterate through the input string char by char.
for(i=0,j=0;str[i];)
{
if (str[i] == ' ')
{
str[j++] = str[i++];
continue;
}
// if the char is not hashed.
if(!hash[str[i] - 'a'])
{
...
#include <stdio.h>
#include <string.h>
int hash[26] = {0};
static int in_valid_range (char c);
static int get_hash_code (char c);
static char *
remove_repeated_char (char *s)
{
size_t len = strlen (s);
size_t i, j = 0;
for (i = 0; i < len; ++i)
{
if (in_valid_range (s[i]))
{
int h = get_hash_code (s[i]);
if (!hash[h])
{
s[j++] = s[i];
hash[h] = 1;
}
}
else
{
s[j++] = s[i];
}
}
s[j] = 0;
return s;
}
int
main (int argc, char **argv)
{
printf ("%s\n", remove_repeated_char (argv[1]));
return 0;
}
static int
in_valid_range (char c)
{
return (c >= 'a' && c <= 'z');
}
static int
get_hash_code (char c)
{
return (int) (c - 'a');
}
char *s;
int i = 0;
for (i = 0; s[i]; i++)
{
int j;
int gap = 0;
for (j = i + 1; s[j]; j++)
{
if (gap > 0)
s[j] = s[j + gap];
if (!s[j])
break;
while (s[i] == s[j])
{
s[j] = s[j + gap + 1];
gap++;
}
}
}

Resources