Looping through an array in C - c

Just wondering if someone could explain this to me? I have a program that asks a user to input a sentence. The program then reads the user input into an array and changes all of the vowels to a $ sign. My question is how does the for loop work? When initialising char c = 0; does that not mean that the array element is an int? I can't understand how it functions.
#include <stdio.h>
#include <string.h>
int main(void)
{
char words[50];
char c;
printf("Enter any number of words: \n");
fgets(words, 50, stdin);
for(c = 0; words[c] != '\n'; c++)
{
if(words[c] =='a'||words[c]=='e'||words[c]=='i'||words[c]=='o'||words[c]=='u')
{
words[c] = '$';
}
}
printf("%s", words);
return 0;
}

The code treats c as an integer variable (in C, char is basically a very narrow integer). In my view it would be cleaner to declare it as int (perhaps unsigned int). However, given that words is at most 50 characters long, char c works fine.
As to the loop:
c = 0 initializes c to zero.
words[c] != '\n' checks -- right at the start and also after each iteration -- whether the current character (words[c]) is a newline, and stops if it is.
c++ increments c after each iteration.

An array is like a building, you have several floors each one with a number.
In the floor 1 lives John.
In floor 2 lives Michael.
If you want to go to Jonh apartment you press 1 on the elevator. If you want to go to Michael's you press 2.
Thats the same with arrays. Every position in the array stores a value, in this case a letter.
Every position has a index associated. The first position is 0.
When you want to access a position of the array you use array[position] where position is the index in the array that you want to access.
The variable c holds the position to be acessed. When you do words[c] you're acctualy accessing the cnt position in the array and retrieving its value.
Supose the word is cool
word[1] results in o,
word[0] results in c
To determine the end of the word, a the caracter \n is set at the last position of the array.

Not really, char and int are implicitly converted.
You can look at a char in this case as a smaller int. sizeof(char) == 1, so it's smaller than an int, that's probably the reason it was used. Programatically, there's no difference in this case, unless the input string is very long, in which case the char will overflow before an int does.

Number literals (such as 0 in your case) are compatible with variables of type char. In fact, even a character literal enclosed in single quotes (for example '\n') is of type int but is implicitly converted to a char when assigned or compared to another char.
Number literals are interchangeable with character literals, as long as the former do not exceed the range of a character.
The following should result in a compiler warning:
char c = 257;
whereas this will not:
char c = 127;

A char is C is an integral type as is short, int, long, and long long (and many other types):
It is defined as the smallest addressable unit on the machine you are compiling on and will usually be 8 bits which means it can hold values -128 to 127. And an unsigned char can hold values 0 - 255.
It works as an iterator in the above since it will stop before 50 all the time and it can hold values up to 127. Whereas an int type can usually hold values up to 2,147,483,647, but takes up 4 times the space in the machine as an 8 bit char. An int is only guaranteed to be at least 16 bits in C which means values between −32,768 and 32,767 or 0 - 6,5535 for an unsigned int.
So your loop is just accessing elements in your array, one after the other like words[0] at the beginning to look at the first character, then words[1] to look at the next character. Since you use a char, which I'm assuming is 8 bits on your machine as that is very common. Your char will be enough to store the iterator for your loop until it gets above 127. If you read in more than 127 characters (instead of just 50) and used a char to iterate you would run into weird problems since the char can't hold 128 and will loop around to -128. Causing you to access words[-128] which would most likely result in a Segmentation Fault.

Related

Char string length not getting initialized properly despite literally putting in the integer size I want it to be?

I'm working with char arrays in C. I'm setting the size in a previous step. When I print it out it clearly shows the num_digits as 1.
But then when I put it in to set the size of a char array to make it a char array of size num_digits, its setting the size of the array as 6.
In the next step when I print strlen(number_array), it prints 6. Printing it out I get something with a lot of question marks. Does anyone know why this is happening?
int num_digits = get_num_digits(number);
printf("Num digits are %d\n", num_digits);
char number_array[num_digits];
printf("String len of array: %d\n", strlen(number_array));
You need to null terminate your array.
char number_array[num_digits + 1];
number_array[num_digits] = '\0';
Without this null terminator, C has no way of know when you've reached the end of the array.
just use 'sizeof' instead of 'strlen'
printf("String len of array: %d\n", sizeof(number_array));
There are a couple possible issues I see here:
As noted in Michael Bianconi's answer, C character arrays (often called strings) require null terminators. You would explicitly set this this with something like:
number_array[number + 1] = '\0'; /* See below for why number + 1 */
Rather than just setting the last element to null, pre-initializing the entire character array to nulls might be helpful. Some compilers may do this for you, but if not you'll need to do this explicitly with something like:
for (int i = 0; i < num_digits + 1; i ++) number_array[i] = '\0';
Note that with gcc I had to use C99 mode using -std=c99 to get this to compile, as the compiler didn't like the initialization within the for statement.
Also, the code presented sets the length of the character array to be the same length as number's length. We don't know what get_num_digits returns, but if it returns the actual number of significant digits in an integer, this will come up one short (see above and other answer), as you need an extra character for the null terminator. An example: if the number is 123456 and get_number_digits returns 6, you would would need to set the length of number_array to 7, instead of 6 (i.e. number + 1).
char number_array[num_digits]; allocates some space for a string. It's an array of num_digits characters. Strings in C are represented as an array of characters, with a null byte at the end. (A null byte has the value zero, not to be confused with the digit character '0'.) So this array has room for a string of up to num_digits - 1 characters.
sizeof(number_array) gives you the array storage size. That's the total amount of space you have for a string plus its null terminator. At any given time, the array can contain a string of any length up to number_array - 1, or it might not contain a string at all if the array doesn't contain a null terminator.
strlen(number_array) gives you the length of the string contained in the array. If the array doesn't contain a null terminator, this call may return a garbage value or crash your program (or make demons fly out of your nose, but most computers fortunately lack the requisite hardware).
Since you haven't initialized number_array, it contains whatever happened to be there in memory before. Depending on how your system works, this may or may not vary from one execution of the program to the next, and this certainly does vary depending on what the program has been doing and on the compiler and operating system.
What you need to do is:
Give the array enough room for the null terminator.
Initialize the array to an empty string by making setting the first character to zero.
Optionally, initialize the whole array to zero. This is not necessary, but it may simplify further work with the array.
Use %zu rather than %d to print a size. %d is for an int, but sizeof and strlen return a size_t, which depending on your system may or may not be the same size of integers.
char number_array[num_digits + 1];
number_array[0] = 0; // or memset(number_array, 0, sizeof(number_array));
printf("Storage size of array: %zu\n", sizeof(number_array));
printf("The array contains an empty string: length=%zu\n", strlen(number_array));

Why does this variable equal a number and a character?

While debugging this code snippet here:
int main () {
char str[] = "Stackoverflow";
char a = *str;
return 0;
}
Why does a show as 83 'S'?
I think you might want to have more than one thing clarified:
First, pointer str points to the first character of a sequence of character values in memory, i.e. S, t, a, ...
Then, *str dereferences this pointer, i.e. it reads the value of the character to which str points. Hence *str yields S.
Statement char a = *str assigns the value S to variable a of type char, which represents a portion of memory capable of storing one character. Usually, char is an 8 bit signed (or unsigned) integral value, and any simple character is therefore represented by a value between -127 and +128 (the range of signed 8 bit values). The character value S, for example, seems to be represented as integral value 83 according to ASCII. Whether a system uses ASCII or some other character set is system defined, but ASCII is by far the most common character set today.
So S and 83 are actually the same thing, it's just that when a terminal interprets value 83 to be printed as character, it prints S. The other way round, if we interpret S as integral value, a terminal would print 83:
#include <stdio.h>
int main() {
printf("'S' as integral value: %d\n", 'S');
printf("83 as character value: %c\n", 83);
char c1 = 'S';
char c2 = 83;
if (c1 == c2) {
printf("c1 and c2 are equal.\n");
} else {
printf("c1 and c2 are not equal.\n");
}
}
Output:
'S' as integral value: 83
83 as character value: S
c1 and c2 are equal.
83 is the ASCII code for uppercase letter 's'.
*str is equal to writing str[0] so in this case the first memory slot of the array str which corresponds to the character 'S'
Computers understand everything as numbers: Characters, strings, photos, videos, audio ... etc. Everything is a number inside a computer and thus people wondered how to represent characters.
And because of this fact, they decided to encode characters as numbers so that every character has a corresponding number that encodes it inside the computer.
Throughout history, many character encoding schemes (A matching between characters and numbers) have been worked out but one of them is very famous and almost used everywhere : It's called ASCII character encoding. ASCII is a 7-bits encoding that represents all numerical characters and Latin alphabet characters (Uppercase and lowercase) beside some other symbols.
By default, your system provides ASCII input to your C program and thus, internally, this input is stored in memory as ASCII standard says. For instance, when you type A on your keyboard, the keyboard sends the value 65 (This is the decimal value of the character A in the ASCII standard. Internally, it is sent as a sequence of 1000001101 because computers work in binary) to your program. Your program stores this value (65) inside a memory location specified by a variable (char c;). When you ask the computer to print this character, it checks the ASCII value stored in the character's variable and then figures out a way how to draw the matching symbol on the screen.
In C, strings are just a sequence (Or an array) of characters. When you hold a pointer to a string, it actually points to the first character of the string (The character array). If you advance the pointer by 1, you will point to the second character and so on. So, if you dereference your original pointer (That points to the first character), you will get the ASCII value of the character stored in that position (The first position) and thus in your case you get 83 which corresponds to the symbol 'S'.
The program below shows all ASCII characters and their graphical representation : Some few characters might not have a visual representation because they are used for controlling input and terminal, especially, the first few characters (First 34 values).
#include <stdio.h>
int main ()
{
/* Unsigned to avoid integer overflow in the loop below */
unsigned char c;
/* ASCII is 7-bit so it can represent
2^7 = 128 (from 0 to 127) symbols */
for (c = 0; c < 128; c++)
printf ("ASCII value of %c = %d\n", c, c);
return 0;
}

Calling the 1's, 10's, 100's... columns of an integer using a string array

I'm trying to convert a long long integer to a string array with the 1's column in position 0 of the array, the 10's column in position 1, the 100's column in position 2, like this:
INPUT: 4444555566667777 -----> OUTPUT: [4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7]
To test my code, I wrote for my last line printf("%d\n",number_str[3]). I expected my program to output the value of position 4, "7". Instead, it output "52". Changing my last line to printf("%d\n",number_str[4]) yields "53" instead of "6", as I expected. Can anyone explain what's going on?
Surely 52 and 53 correspond to ASCII values, but then, how can I convert them to integers? Can I do this in line?
Where I'm headed with this part of my program is to add up all of the numbers in the 10's, 1,000's, 100,000's, 10,000,000's... columns. Every other digit in a base-10 credit card number. This is one step in my attempt at a Luhn validation.
// Libraries
#include <cs50.h>
#include <stdio.h>
#include <string.h>
// Program
int main(void)
{
// Get CC number
printf("Enter your credit card number: ");
long long number_ll = GetLongLong();
// printf("%lld\n", number_ll);
// Convert long long to string
char number_str[64];
sprintf(number_str, "%lld", number_ll);
// printf("%s\n", number_str);
// Get length of card number string
int cclength = strlen(number_str);
// Check the length of card number string
if ( ! (cclength == 13 || cclength == 15 || cclength == 16))
printf("INVALID\n");
else
printf("%d\n",number_str[3]);
To convert ascii into integer use
#include <stdlib.h>
int atoi(const char *str);
change this
printf("%d\n",number_str[3]);
to
char buf[2];
buf[0]=number_str[3];
buf[1]='\0';
printf("%d\n",atoi((const char*)buf));
Using "%d" on a char will print its ASCII code. Use "%c" to print itself.
And your string's order is reversed compared to your purpose. The rightmost digit(1's column) is at the tail of the string, and the leftmost one is in position 0.
So to print the number at position i (count from right to left), you should use:
printf("%c\n", number_str[cclength - i - 1]);
I'm going to go ahead and expand on my comment since I don't believe either of the other answers responded to your full question.
By reading the CC number into a long long, and then using sprintf to plug the number into a character array, I would say you're correctly getting the number into a form that you can use for validation. In fact, you can check the return value of sprintf to see whether or not it's a valid number (although a failure case would be unlikely since you're plugging in a long long.
Once you have the CC number in a character array, you know that each element of the array will contain one character, which corresponds to one digit in the CC number. It sounds like for your purposes, it's more useful for the values in the array to be the decimal values, rather than the ASCII values. Logically, this is the difference between the values '0' and 0. You can look up any ASCII chart to see the corresponding ASCII value for each character, but since characters can be manipulated just like integers, you can traverse the array:
for(i = 0; i < 64; i++) num_str[i] -= '0';
Note that this doesn't handle there being less than 64 characters or uninitialized values in the array after the CC number characters, so you'll need to modify it. What's important to realize is that you're just shifting the character values down by '0', which happens to have the integer value 48.
Once you do this conversion, printing out a value in the array with printf using %d as the format specifier will work like you expect; even though the array data type is char, each element may be printed as a decimal integer.
Once you've read the number into the char array and made the conversion, all you need to do is traverse the array again, performing whatever steps are involved in the CC Validation process. You may need to traverse the array in reverse if the validation method requires the digits to be in order.

Char Data type variables

I'm studying a book called "Learn C on the Mac". It defines the char data type as a 1 byte data type. Does that mean that a variable with char data type can NOT hold an integer such as 5000? I'm confused by this. The book has an example program assigning a variable data type as char, with 5000 in the variable. It is actually a string, 5000 long. Example: (char rating[5000];). I thought char could only hold the ascii set or the numerical value? Sorry I am fairly new to programming.
Does that mean that a variable with char data type can NOT hold an integer such as 5000?
No. On a platform where a byte is extremely long, it is theoretically possible that char be able to hold the value 5000.
However, that has nothing to do with the example you read. This:
char rating[5000];
creates an array of 5000 chars. It is not initializing rating with the value 5000. Are you confusing this with the parentheses-initialization syntax of C++? That would be
char rating(5000);
and it does something entirely different. And it wouldn't be valid C at all anyway.
char rating[5000] means an array of 5000 characters. That is, it will occupy an space of 5000 * sizeof(char) in the memory.
char rating[5000] will create an array with 5000 char elements.
the char data type as a 1 byte data type. Does that mean that a variable with char data type can NOT hold an integer such as 5000?
Char refers to character. As you already know, a char variable holds a space of 1 byte. It can, therefore, hold exactly one digit or one letter—no more, no less. Char values are one-character values.
So that means—a variable with char data type cannot hold an integer such as 5000. There isn't enough space for it on the computer memory. If you input a value with more than one character (e.g. 5000), only the first character will be accepted. You cannot feed such data to a char variable.
Use this program to better your understanding.
#include <stdio.h>
main()
{
char s;
scanf("%c", &s);
printf("%c", s);
return (0);
}
Try inputting 5000 and observe what the program prints as output.
an example program assigning a variable data type as char, with 5000 in the variable. It is actually a string, 5000 long. Example: (char rating[5000];).
In case you didn't know, a string is an array of char (i.e. characters). char rating[5000]is declaring a string data type. It defines rating as a string of 5000 chars, that is, a string 5000 characters long. However, it is not initializing rating with the value 5000. Wrong interpretation: char rating='5000' Rather, it is declaring the size of rating to be 5000.
I thought char could only hold the ascii set or the numerical value.
Yes, you are right about the ascii part. A char variable can hold any one ascii value at any time. Letters, digits, and symbols altogether form the ascii set. But, numerical values don't fall into this category. Numerical value is the magnitude, which isn't necessarily made of only one digit. Digits (i.e. numerals from 0 to 9) is the right term for it.
To sum up, char is a data type which can store the value of a letter / alphabet or a digit / number. A string is a group of char. 'a' or '1' can be a char data, but a phrase or a sentence can't. To store a group of characters into a variable, use string. Remember these simple facts to make your life easy.

New to C: whats wrong with my program?

I know my way around ruby pretty well and am teaching myself C starting with a few toy programs. This one is just to calculate the average of a string of numbers I enter as an argument.
#include <stdio.h>
#include <string.h>
main(int argc, char *argv[])
{
char *token;
int sum = 0;
int count = 0;
token = strtok(argv[1],",");
while (token != NULL)
{
count++;
sum += (int)*token;
token = strtok(NULL, ",");
}
printf("Avg: %d", sum/count);
printf("\n");
return 0;
}
The output is:
mike#sleepycat:~/projects/cee$ ./avg 1,1
Avg: 49
Which clearly needs some adjustment.
Any improvements and an explanation would be appreciated.
Look for sscanf or atoi as functions to convert from a string (array of characters) to an integer.
Unlike higher-level languages, C doesn't automatically convert between string and integral/real data types.
49 is the ASCII value of '1' char.
It should be helpful to you....:D
The problem is the character "1" is 49. You have to convert the character value to an integer and then average.
In C if you cast a char to an int you just get the ASCII value of it. So, you're averaging the ascii value of the character 1 twice, and getting what you'd expect.
You probably want to use atoi().
EDIT: Note that this is generally true of all typecasts in C. C doesn't reinterpret values for you, it trusts you to know what exists at a given location.
strtok(
Please, please do not use this. Even its own documentation says never to use it. I don't know how you, as a Ruby programmer, found out about its existence, but please forget about it.
(int)*token
This is not even close to doing what you want. There are two fundamental problems:
1) A char* does not "contain" text. It points at text. token is of type char*; therefore *token is of type char. That is, a single byte, not a string. Note that I said "byte", not "character", because the name char is actually wrong - an understandable oversight on the part of the language designers, because Unicode did not exist back then. Please understand that char is fundamentally a numeric type. There is no real text type in C! Interpreting a sequence of char values as text is just a convention.
2) Casting in C does not perform any kind of magical conversions.
What your code does is to grab the byte that token points at (after the strtok() call), and cast that numeric value to int. The byte that is rendered with the symbol 1 actually has a value of 49. Again, interpreting a sequence of bytes as text is just a convention, and thus interpreting a byte as a character is just a convention - specifically, here we are using the convention known as ASCII. When you hit the 1 key on your keyboard, and later hit enter to run the program, the chain of events set in motion by the command window actually passed a byte with the value 49 to your program. (In the same way, the comma has a value of 44.)
Both of the above problems are solved by using the proper tools to parse the input. Look up sscanf(). However, you don't even want to pass the input to your program this way, because you can't put any spaces in the input - each "word" on the command line will be passed as a separate entry in the argv[] array.
What you should do, in fact, is take advantage of that, by just expecting each entry in argv[] to represent one number. You can again use sscanf() to parse each entry, and it will be much easier.
Finally:
printf("Avg: %d", sum/count)
The quotient sum/count will not give you a decimal result. Dividing an integer by another integer yields an integer in C, discarding the remainder.
In this line: sum += (int)*token;
Casting a char to an int takes the ASCII value of the char. for 1, this value is 49.
Use the atoi function instead:
sum += atoi(token);
Note atoi is found in the stdlib.h file, so you'll need to #include it as well.
You can't convert a string to an integer via
sum += (int)*token;
Instead you have to call a function like atoi():
sum += atoi (token);
when you cast a char (which is what *token is) to int you get its ascii value in C - which is 49... so the average of the chars ascii values is in fact 49. you need to use atoi to get the value of the number represented

Resources