Converting Character Array to Integer Array in C for ISBN Validation - c

I really hope someone can give a well explained example. I've been searching everywhere but can't find a proper solution.
I am taking an introduction to C Programming class, and our last assignment is to write a program which validates a 10 digit ISBN with dashes... The ISBN is inputted as a string in a CHAR array. From there I need to separate each digit and convert them into an integer, so I can calculated the validity of the ISBN. On top of that, the dashes need to be ignored..
My thought process was to create an INT array and then use a loop to store each character into the array, and pass it through the atoi() function. I also tried using an IF statement to check each part of the CHAR array to see if it found a dash. If it did find one, it would skip to the next spot in the array. It looked something like this:
int num[12], i = 0, j = 0, count = 0;
char isbn[12];
printf ("Enter an ISBN to validate: ");
scanf ("%13[0-9Xx-]%*c", &isbn);
do {
if (isbn[i] == '-') {
i++;
j++;
}
else {
num[i]= atoi(isbn[j]);
i++;
j++;
}
count++;
} while (count != 10);
But that creates a segmentation fault, so I can't even tell if my IF statement has actually filtered the dashes....
If someone could try and solve this I'd really appreciate that. The Assignment was due Dec 4th, however I got an extension until Dec 7th, so I'm pressed for time.
Please write out the code in your explanation. I'm a visual learner, and need to see step by step.
There's obviously a lot more that needs to be coded, but I can't move ahead until I get over this obstacle.
Thanks in advance!

First of all, your definition of isbn is not sufficient to hold 13 characters; it should therefore be 14 chars long (to also store the terminating '\0').
Second, your loop is overly complicated; three loop variables that maintain the same value is redundant.
Third, the loop is not safe, because a string might be as short as one character, but your code happily loops 10 times.
Lastly, converting a char that holds the ascii value of a digit can be converted by simply subtracting '0' from it.
This is the code after above improvements have been made.
#include <stdio.h>
int main(void)
{
int num[14], i;
char isbn[14], *p;
printf("Enter an ISBN to validate: ");
scanf("%13[0-9Xx-]%*c", &isbn);
// p iterates over each character of isbn
// *p evaluates the value of each character
// the loop stops when the end-of-string is reached, i.e. '\0'
for (p = isbn, i = 0; *p; ++p) {
if (*p == '-' || *p == 'X' || *p == 'x') {
continue;
}
// it's definitely a digit now
num[i++] = *p - '0';
}
// post: i holds number of digits in num
// post: num[x] is the digit value, for 0 <= x < i
return 0;
}

Related

Segmentation fault at writing the telephone number program

I am writing a C program that prompts the user to enter a telephone number in the form (xxx)xxx-xxxx and then displays the number in the format xxx.xxx.xxxx. Here is an example:
Enter a phone number [(xxx) xxx-xxxx]: (404)817-6200
You entered the data 404.817.6200
I created two strings, one for storing the phone number with parenthesis and '-' signs and the other, empty. I want to add each character to the empty string, changing the ')' and '-' to '.'. Here is my code:
#include <stdio.h>
int main(void){
char num[15];
char phone[13];
int i = 1;
int j = 0;
printf("Please, enter your phone number in the format (xxx)xxx-xxxx:");
scanf("\n%s", num);
while(num != '\0'){
if(num[i] == ')' || num[i] == '-'){
phone[j] = '.';
}else{
phone[j] = num[i];
}
i++;
j++;
}
printf("\n%s",phone);
}
When I run the program, it gives me the error message that says:
Segmentation fault
Can somebody explain why it is happening and how to prevent it in the future?
I see three issues in your program:
(1) while(num != '\0') should be while(num[i] != '\0'. num is an array (and will never compare equal '\0', so you get an endless loop and exceed array bounds.
(2) you need at least 14 bytes for phone (just one less than num, not two less)
(3) you need to write a string termination character into phone; othwerwise printf("\n%s",phone); will again exceed the bounds of phone; e.g:
}
phone[j] = '\0';
printf("\n%s",phone);`
When you reference the name of an array variable in C, without appending the [] (index) operator, you are (effectively) referring to the address of that array's first element. This will never be zero (or NULL) for an array declared as a local variable, so the comparison of num to zero ('\0') in your while loop will never be true, and the loop will run on unstopped, until you try to read or write to an invalid address, at which point the program will crash.
With compiler warnings enabled, you should see something like the following (generated by clang-cl):
warning : comparing a pointer to a null character constant; did you
mean to compare to NULL? [-Wpointer-compare] warning : comparison
of array 'num' not equal to a null pointer is always true
[-Wtautological-pointer-compare]
What you should do, instead, is to compare the 'current' element (at index i) to the nul character ('\0') to check for the end of the string:
while (num[i] != '\0') {// Check character at position "i"
// rest of your loop ...
You should also ensure that your phone string is properly nul-terminated (although some compilers will initialize the array to zero, don't rely on this). You can do this either by adding an initializer to the declaration of phone:
char phone[13] = { 0 }; // Will set all elements to zero
or by adding the nul terminator immediately after the end of your while loop:
// body of while loop
// ...
}
phone[j] = '\0'; // Append the terminator

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.

How to sort characters in a string alphabetically using scanf() and saved character in buffer? [duplicate]

This question already has answers here:
What would be the simplest way to alpha sort an array of chars in C?
(7 answers)
Closed 7 years ago.
Hi I'm pretty new to using C.
My teacher told me to code a function to sort characters in a string alphabetically by using array & the fact that when a scanf() a string, the first character is called and the rest are saved in the buffer.
(I haven't learnt about pointers yet.)
For example, if I type in badf and space(signalling "an end", or the sentinel value for end of string), the function should return abdf.
I'm stuck here. It's my first ever stackoverflow question! Please help. Thanks.
#include <stdio.h>
#include <string.h>
int main() {
char arr[100];
char front_char, first_char;
// set the variables
int i, j, k, l;
printf("Enter a string and press space to end\n");
// get the input using scanf, which will just get the first character and save the rest in buffer
scanf("%c", &first_char);
// assign the first_character in arr[0] for initialization
arr[0] = first_char;
// 32 is "space" in ascii code. Space is used as a sentinel value. User is supposed to press space at the end of the String
while(front_char != 32) {
// get the "second" character from buffer and ass. repeat this until the next character in buffer is 32, or "space"
scanf("%c" , &front_char);
// load character from buffer, and check if its assigned number in ascii code is smaller than characters in array
for(i = 1; front_char != 32; i++) {
for(j = 0; j < i; j++) {
// go through the previously aligned array to compare the ascii number of the loaded character from buffer
if(arr[j] <= front_char) {
continue;
} else {
// run through the previously aligned array, and if a character with bigger ascii number comes up,
for(k = i-1; k >= j; k--) {
// assign/push the values in array to the next index(i don't know how to describe this, but I hope you see what I mean..)
arr[k+1] = arr[k];
}
}
// assign the loaded character according its ascii number size
arr[j] = front_char;
}
}
// print the result
for(l = 0 ; l < i ; l++){
printf("%c", arr[l]);
}
}
return 0;
}
To get to your final solution, you have to get through three intermediate steps:
Read in the string successfully
Address individual characters in the string
Transpose characters in the string
You definitely have bugs (ameyCU's answer).
Try first to read in the string, and just print it out again; no other action.
When you've got that, try to read in the string, then print it out character-by-character.
If you can do that, you're ready for step 3 and almost done.
EDIT: also, when you get there,
while(front_char != ' ')
is better than != 32; it's more reliable and much easier to read and understand.
For example, if I type in badf and space(signalling "an end", or the sentinel value for end of string)
You want to take input as string ex-badf but your are taking input in a character variable.
scanf("%c" , &first_char);
Second -
while(front_char != 32)
Checking if front_char is space or not but front_char does not have any value stored in it.
Program will crash as soon as you give input !!

Simple C If Statement

I made a very simple C program that is supposed to count how many characters and words are in a string (I count words by checking how many spaces are in the text and one to it). The current code is the following (with no 'printf's to keep it shorter):
int main(int argc, char *argv[])
{
int character;
int words, characters = 0;
while ((character = getchar()) != '\n') {
characters = ++characters;
if ((character == ' ') || (character == '\d')) {
words = ++words;
}
}
return 0;
}
My problem is that counting words do not work. I get an accurate count for characters, but words always gives me 2293576, and I cannot for the world figure out why.
Can someone solve this mystery for me?
Thank you for all your answers; I really appreciate the help.
and sorry if my primitive skills made some of your heads hurt. I am a beginner but hopefully improve fast.
You haven't initialized words. Uninitialized local variables in C default to an undefined value and are not automatically initialized to zero.
The statement
int x, y = 0;
Is not the same as
int x = 0, y = 0;
You don't initialize words to 0. Also, change this:
characters = ++characters;
to just:
characters++;
(and for words too).
Also, what is the '\d' character (besides a plain old d)?
You fail to initialize "words". In the statement:
int words, characters = 0;
characters is assigned to 0, but words is left unintialized so it could contain any integer value. The rest of your code then modifies words in its unintialized state. Instead of starting at 0 and counting up, words is starting at something like 2293576 and counting up from there. To fix your code assign words to 0 as well as characters before using them in the for loop.
int words = 0, characters = 0;

How to erase every occurences of vowels in a string

In a schools assignment we are asked to remove every occurences of vowels from a string.
So:
"The boy kicked the ball" would result in
"Th by kckd th bll"
Whenever a vowel is found, all the subsequent characters somehow have to shift left, or at least that's my approach. Being that I just started learning C, it may very well be that it's a ridiculous approach.
What I'm trying to do is: When I hit the first vowel, I "shift" the next char ([i+1]) to the current pos (i). the shifting then has to continue for every subsequent character, so int startshift is set to 1 so the first if block excecutes on every subsequent iteration.
The first if block also test to see if the next char is a vowel. Without such a test any character preceding a vowel would "transform" to the adjacent vowel, and every vowel except the first would still be present. However this resulted in every vowel being replaced by the preceding char, hence the if else block.
Anyway, this ugly code is what I've come up with so far. (The names used for the char* pointers make no sense (I just don't know what to call them), and having two sets of them is probably redudant.
char line[70];
char *blank;
char *hlp;
char *blanktwo;
char *hlptwo;
strcpy(line, temp->data);
int i = 0;
int j;
while (line[i] != '\n') {
if (startshift && !isvowel(line[i+1])) { // need a test for [i + 1] is vowel
blank = &line[i+1]; // blank is set to til point to the value of line[i+1]
hlp = &line[i]; // hlp is set to point to the value of line[i]
*hlp = *blank; // shifting left
} else if (startshift && isvowel(line[i+1])) {
blanktwo = &line[i+1];
hlptwo = &line[i];
*hlptwo = *blanktwo;
//*hlptwo = line[i + 2]; // LAST MOD, doesn't work
}
for (j = 0; j < 10; j++) { // TODO: j < NVOWELS
if (line[i] == vowels[j]) { // TODO: COULD TRY COPY EVERYTHING EXCEPT VOWELS
blanktwo = &line[i+1];
hlptwo = &line[i];
*hlptwo = *blanktwo;
startshift = 1;
}
}
i++;
}
printf("%s", line);
The code doesn't work.
with text.txt:
The boy kicked the ball
He kicked it hard
./oblig1 remove test.txt produces:
Th boy kicked the ball
e kicked it hard
NB. I've omitted the outer while loop used for iterating the lines in the text file.
Just some food for thought, since this is homework and I don't want to spoil the fun:
You might also tackle this problem without using a second 'temp->data' buffer. If the given input string is in a modifiable memory chunk, like
char data[] = "The boy kicked the ball";
You could also write a program which maintains two pointers into the buffer:
One pointer points to the position in the string where the next vowel would need to be written; this pointer is advanced whenever a vowel was written.
The second pointer points to the position in the string where the next character to consider is read from; this pointer is advanced whenever a character is read.
If you think about it, you can see that the first pointer will not advance as fast as the second pointer (since every character is read, but not every character is written out - vowels are skipped).
If you go for this route, consider that you may need to terminate the string properly.
Try use std containers and objects
#include <iostream>
#include <string>
#include <vector>
std::string editStr = "qweertadoi";
std::vector<char> vowels{'i', 'o', 'u', 'e', 'a'};
int main() {
for(unsigned int i = 0; i<editStr.size(); i++){
for(char c: vowels){
if(editStr.at(i) == c){
editStr.erase(i--,1);
break;
}
}
}
std::cout << editStr << std::endl;
return 0;
}

Resources