This question already has answers here:
How do I determine the size of my array in C?
(24 answers)
Closed 3 years ago.
Is there a way, I can use of strlen() to find the length of the arrays, instead of specifying in the loop.
First Code: Working With x < 4 Which is the size of the array of temps[4].
#include <stdio.h>
#include <string.h>
int main(){
float temps[4] = {72.5, 73.4, 74.7, 75.2};
int x;
printf("Local Temperatures\n");
for(x = 1; x < 4; x++){
printf("Station %d: %.1f\n",x,temps[x]);
}
}
My Second Code, Not Working, But Looking At What, I Am Trying To achieve with strlen() to find the size of the array.:
#include <stdio.h>
#include <string.h>
int main(){
float temps[4] = {72.5, 73.4, 74.7, 75.2};
int x;
float size;
size = temps;
printf("Local Temperatures\n");
for(x = 1; x < strlen(size); x++){
printf("Station %d: %.1f\n",x,size[x]);
}
}
strlen is effectively an optimized version of the following:
size_t len = 0;
const char *p = s;
while (!*p) {
++len;
++p;
}
You can easily adapt that.
size_t len = 0;
const float *p = s;
while (*p != 0.0) {
++len;
++p;
}
Of course, that means you need a sentinel value just like you had for the string.
float temps[] = { 72.5, 73.4, 74.7, 75.2, 0.0 };
While you can use a value other than 0.0 as your sentinel value, using a sentinel value might not be desirable, so you might not really want to take the same approach as one does for strings.
For an array (as opposed to a pointer), you can use the following to determine the number of elements in the array:
sizeof(a)/sizeof(*a)
That means you can use the following to determine the number of elements in temps:
sizeof(temps)/sizeof(*temps)
Simple method is to get the size of a array is by sizeof(temps)/sizeof(temps[0])
something like,
for(x = 0; x < sizeof(temps)/sizeof(temps[0]); x++){
printf("Station %d: %.1f\n",x,temps[x]);
}
Note: In your snippet array access is done from 1 to (size) instead 0 to (size-1) which is out of bound access.
Short answer: no.
strlen expects an argument of type char *, which points to the first character of a string, which is a sequence of character values including a zero-valued terminator. strlen returns the number of characters before the terminator:
/**
* A naive implementation of strlen. Actual implementations
* are a little more clever.
*/
size_t strlen( const char *str )
{
size_t count = 0;
while( str[count] )
count++;
return count;
}
The important thing to remember is that strlen returns the length of the string, not the size of the array containing the string. If you have something like
char foo[1024] = “bar”;
the strlen( foo ); returns 3.
If you tried to pass an integer or floating point array to strlen the compiler would yell at you because of the wrong argument type. You could work around this by casting the argument to char *, but you would still likely get a wrong answer, not only because integer and float types are multiple chars wide, but also because such a value may have an embedded zero-valued byte. For example, the integer value 16 is represented as the bytes 0x00, 0x00, 0x00, 0x10. If that’s the first element of your integer array, then strlen would return 0 on a big-endian platform and 1 on a little-endian platform.
If you defined the array, then you know how big it is. If you’re writing a function that receives an array argument, then you must either also receive the size as a separate argument, or you must rely on the presence of a sentinel value in the array.
Just do this to get the length of your float array,
int main()
{
float ar[4] = {1.1,1.2,1.3,1.4};
float b;
printf("Array Size : %d\n",sizeof(ar)/sizeof(b));
return 0;
}
You'll get the total number of element of your array , which you can use further in a loop to print the elements of array.
Note: Do not Use sizeof in case of pointers.
strlen() takes a "const char *" type value as argument. So it cannot be used with integer or float arrays.
Related
I'm trying to convert a decimal value into a string. I use the STM32CubeIDE IDE but am getting an error like 'Invalid binary operator'. I'm able to set &n to the decimal value 3695. I need to convert that into a string. How would I do that?
void main()
{
uint8_t TxArr;
uint16_t Data;
int a[10];
int i;
while (1)
{
HAL_I2C_Master_Transmit(&hi2c1,0x16, &TxArr, 1, 1000);
HAL_I2C_Master_Receive(&hi2c1, 0x17, &Data, 2, 1000);
for(i=0;i<4;i++)
{
a[i]=Data%10+0x30; //value in Data is 3695.
Data=Data/10;
HAL_UART_Transmit(&huart3, a[i], 11, 100);
HAL_Delay(300);
}
}
The error is produced by:
n = n / 10;
What this would do if n was a pointer (int* n) is that it would repoint n to a location one tenth the original number. You will need to begin using normal array operators if you want your code to work properly.
The second problem you have is the following:
You declare n as a array of 10 integers of type and with int.
int n[10];
Then in your for loop you try to do this:
n > 0;
This is an invalid operation as n wil decay into a pointer and as such the address of your array is compared to 0. This will always evaluate as TRUE!
A good way to convert a integer to a string (char array) is this answer.
In your sitaution that would be
int yourToBeConvertedNumber;
char str[INT_MAX]; // or any other reasonable upper bound you have set for the input data.
snprintf(str, sizeof(str), "%d", yourToBeConvertedNumber);
Generally speaking, to convert an integer to a string, you can use the sprintf function. It should be available in newliband even newlib-nano standard C libraries.
However my guess here is that you have an array of integers where each element is a number between 0 and 9 ?
If this is true you have several issues: you seem to handle the variable n like an integer and not an address. Also your string should be one element longer and composed of chars.
You may do something like this:
char a[11];
for(i=0;i<10;i++)
{
a[i]=n[i]%10 +'0';
}
a[11]='\0';
I'm trying to create a program that generates random words from Katakana (Japanese syllables).
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <wchar.h>
#include <locale.h>
char* word;
char *kata[] = {"ア", "イ", "ウ", "エ", "オ", "カ", "キ", "ク", "ケ", "コ", "サ", "シ", "ス","セ","ソ","タ","チ","ツ","テ","ト","ナ","ニ","ヌ",
"ネ","ノ","ハ","ヒ","フ","ヘ","ホ","マ","ミ","ム","メ","モ","ヤ","ユ","ヨ","ラ","リ","ル","レ","ロ","ワ","ヲ","ン","ガ","ギ",
"グ","ゲ","ゴ","ザ","ジ","ズ","ゼ","ゾ","ダ","ヂ","ヅ","デ","ド","バ","ビ","ブ","ベ","ボ","パ","ピ","プ","ペ","ポ","ャ","ュ",
"ョ","ヴ","ァ","ィ","ゥ","ェ","ォ"};
int x = 0;
void generator (int length) {
for (int z=0; z<length; z++) {
x = rand() % sizeof(*kata);
concat(word,kata[x]);
}
}
int main (void) {
srand((unsigned) time(NULL));
int length = rand() % 5 + 2;
generator(length);
puts(word);
}
word is the String that I want to get printed, and kata is a Char Array containing Katakana. However, if I don't include the "*" to make the array an String array, C complains that there are multiple characters in a char. The rest of the code works fine in my testing.
I'm using BoUoW which has a full Ubuntu environment on Windows, so I don't think that's the problem, but rather how I'm putting the String array into the String.
I've done a similar program in Java in about an hour and this has taken me much longer. Although that's probably because I'm new to C.
Lot of check should be added (overflow on word for example)
The number of element on kata is the sizeof kata / sizeof an element you can do a macro countof
strcat is the function you need.
The idea is something like
char *kata[] = {"ア", "イ", "ウ", "エ", "オ", "カ", "キ", "ク", "ケ", "コ", "サ", "シ", "ス","セ","ソ","タ","チ","ツ","テ","ト","ナ","ニ","ヌ
",
"ネ","ノ","ハ","ヒ","フ","ヘ","ホ","マ","ミ","ム","メ","モ","ヤ","ユ","ヨ","ラ","リ","ル","レ","ロ","ワ","ヲ","ン","ガ","ギ",
"グ","ゲ","ゴ","ザ","ジ","ズ","ゼ","ゾ","ダ","ヂ","ヅ","デ","ド","バ","ビ","ブ","ベ","ボ","パ","ピ","プ","ペ","ポ","ャ","ュ",
"ョ","ヴ","ァ","ィ","ゥ","ェ","ォ"};
int x = 0;
static void generator (int nb, char *word, size_t n) {
word[0] = '\0';
while (nb-- > 0) {
x = rand() % (sizeof(kata) / sizeof(char*));
strcat(word, kata[x]);
}
}
int main (void) {
char word[64];
srand((unsigned) time(NULL));
int nb = rand() % 5 + 2;
generator(nb, word, sizeof(word));
puts(word);
return 0;
}
Which book are you reading? The reason I ask is that you've encountered a series of categorical errors regarding the fundamentals of C which people who read good books don't usually encounter. I can recommend K&R2E to someone who's already experienced programming from another language.
word is the String ...
Not in the code you've shown us, no... word contains a null pointer, and in your code you're assigning into that null pointer. Bad news :(
Stop confusing the concept of strings (which are a category of values) with pointers (which are a category of types).
A string is a sequence of character values that terminates at the first '\0'. That's a value. Strings are stored within arrays; an array is a category of type.
A pointer denotes a type which has values that point at/into arrays (which might or might not contain a string), functions or at nothing (which are null pointers).
... kata is a Char Array containing Katakana ...
Again, this isn't the case. kata is an array of char *. char * is not a character type; it's a character pointer type!
However, if I don't include the "*" to make the array an String array, C complains that there are multiple characters in a char.
I'm not sure what you expect. Since the type of a string literal expression such as "ア" is a char[n] (character array type) which gets converted to a char * (character pointer type) with a value pointing at the first character, and you store multiple of those in an array, the type of your array needs to be char *[m]. The * is necessary! I don't see a problem here.
I do see other problems, however. Firstly, concat isn't defined. You've not asked a question about this, so here's the definition I'll use to fill in the blanks:
void concat(char *dest, char *src) {
strcat(dest, src); // `strcat` is from `<string.h>`
}
sizeof(*kata) retrieves the size of a char *, which is commonly four or eight... so rand() % sizeof(*kata) will equate to rand() % 4 or rand % 8 on common systems. Perhaps you meant rand() % (sizeof kata / sizeof *kata). More on that later...
As I mentioned earlier, word is a null pointer and you can't assign into such a pointer. You need to make it point at something. You can do this by:
Using the &address-of operator on a variable. I assume this isn't suitable for you, as you'll want your pointer to point at a sequence of more than one object, but this is helpful to explain anyway. For example:
int x;
int *pointer_to_x = &x;
Declaring an array, and using the identifier of the array, possibly in conjunction with the + addition operator to point at an element in the array. For example:
int array[42];
int *pointer_to_first = array + 0;
int *pointer_to_second = array + 1;
Calling malloc, realloc, calloc or some other function that returns a pointer to a suitably sized object. For example:
int *pointer_to_whatever = malloc(42 * sizeof *pointer_to_whatever);
// Remember to free(pointer_to_whatever) ONCE when you're done with it
int isn't really appropriate for storing array indexes or lengths; you're better off using size_t as that doesn't have negative values which doesn't just eliminate some bugs, but also makes your code a little more efficient.
rand() % sizeof(*kata) isn't very random.
In fact, it's quite predictable. By reseeding with the same seed, another program can reproduce that exact sequence. By iterating on seeds, starting with seed = time(NULL) and moving backwards in time, it's easy enough to prove that this is no less predictable than a single int value, despite the fact that it is in fact multiple character values.
Additionally, rand tends to introduce biases, especially when you use the % operator to reduce it. You need to remove the bias. You could do this by first assigning your random number to a double, then dividing it by RAND_MAX + 1.0 like so:
double rand_double(void) {
return rand() / (RAND_MAX + 1.0);
}
With this function returning a value between 0.0 and 1.0 (excluding 1.0), you should be able to use rand_double() * (sizeof kata / sizeof *kata) for example, and this will be better... but the bias is still there; it's just reduced. To eliminate the bias, you need to consider that rand returns a sequence of values, each of which lie within [0..RAND_MAX], and that your range doesn't divide evenly into that range; the remainder of the division is a huge part of your bias. You need to take the range, and truncate it down to something that does divide evenly! That is, make a function that wraps rand and discards values greater than RAND_MAX - (RAND_MAX % (sizeof kata / sizeof *kata))... I've described (and solved) this problem in a solution I posted on gist, so for your convenience here's an adaptation of that code:
unsigned int rand_range(unsigned int ceiling) {
int n;
do {
n = rand();
} while (RAND_MAX - n <= RAND_MAX % ceiling);
return n % ceiling;
}
This is better again, but you won't want to use anything rand-derived for security purposes, so don't use this for passwords! This is because of the attack described earlier, where people can go back in time by reseeding to produce values previously generated. Use a cryptographically secure random number generator for that.
This is my first time asking so please be gentle lol.
So I am trying to better understand arrays in C. Is there a way I can add an element to an array without using a for loop? The problem is I want to add a new element to the end of the array, but without knowing the size of the array.
So I already have this:
#include <stdlib.h> //not sure if needed but put it just in case
int main(void):
float real[20];
real[]={1,2,3,4,5};
I want to add the number 6 to the array, but I don't want to use real[5]=6. Is there another way to add an element to the end of the array without a loop checking if each element in the array until the element is null? Thanks for your help in advance!
C arrays don't know about their length. If you need arrays that can grow and shrink, you have to keep extra information on how long your active array is. An array that is created on the stack like so:
real array[20] = {1, 2, 3};
will contain twenty elements, the first three initialised with concrete values, the rest initialised to zero. If you want to consider this array as an array of initially three values that can hold up to 20 values, you have to keep the actual array length as an extra variable:
real array[20] = {1, 2, 3};
int narray = 3;
You can then append a value. Take care not to overflow that maximum storage of 20 elements:
if (narray < 20) array[narray++] = 9;
You can read the last value and remove it from the array:
if (narray) printf("%g\n", array[--narry]);
Here, you have to take care not to underflow the array. (Also, don't decrement narray more than once in the same expression, which will lead to undefined behaviour.)
If you write a function that operates on the array, pass both array and length:
void array_print(float array[], int n)
{
int i;
for (i = 0; i < n; i++) {
if (i) printf(", ");
printf("%g", array[i]);
}
printf("\n");
}
and call it like so:
array_print(array, narray);
Another approach is to keep a sentinel value like 0.0. This can be useful in some cases, but it has the disadvantage that you have to traverse the whole array to find out the length. It also removes the sentinel from the range of valid values that your array can hold.
The advantage here is, of course, that the array is "self-contained", i.e. you don't have to pass array and length to a function; just the array is enough. When appending you still have to take care not to overflow the maximum storage, which makes this approach cumbersome.
The only way is to keep a pointer to the next free position in the array. For example
#include <stdio.h>
float * copy( const float *src, size_t n, float *dst )
{
while ( n-- ) *dst++ = *src++;
return dst;
}
int main(void)
{
float real[20];
float *p = real;
p = copy( ( float [] ){ 1, 2, 3, 4, 5 }, 5, p );
p = copy( ( float [] ){ 6, 7 }, 2, p );
for ( float *q = real; q != p; ++q ) printf( "%1.1f ", *q );
printf( "\n" );
return 0;
}
The output is
1.0 2.0 3.0 4.0 5.0 6.0 7.0
You always can check whether p points within the array using condition
p < real + 20
The other approach is to use a structure that contains an array. For example
struct Array
{
enum { N = 20 };
float real[N];
size_t n; /* current number of filled elements */
};
With a little help of the preprocessor, you can use a compound literal to get the size:
int main(void)
{
#define REAL_VALUES 1, 2, 3, 4, 5
float real[20] = {REAL_VALUES};
real[sizeof((float[]){REAL_VALUES}) / sizeof(float)] = 6;
return 0;
}
In C you can get the length of an array with the expression sizeof (array) / sizeof (array)[0], or even better, by defining a macro:
#define LEN(array) \
((int) (sizeof (array) / sizeof (array)[0]))
What you describe is not adding an element to the end of the array but rather adding an element after the last element inserted. For that you need a variable that keeps track of the element count:
int count = 0;
float x;
...
if (count < LEN(real)) {
real[count] = x;
count++;
}
Observe, however, that once you have passed the array to a function its length is gone, so you need to pass the array length to the function as well:
void foo(float a[], int len);
...
foo(real, LEN(real));
You can use memset() to make space for your element in your array and then insert your element at specific position.
Here is sample code below.
/*Make space for number to insert.*/
memmove(&arr[pos+1],&arr[pos],(ARR_SIZE+1-pos)*sizeof(int));
arr[pos] = num;/*insert the number.*/
Full code snipet could be found here InsertElement
If for example I have a ptr to a string and move ptr to last character in string and iterate backwards to beginning of string using *p-- and I iterate to position one before start of array is this OK? Or will I get an access violation? I am only moving pointer - not accessing. It seems to work in my code so wondering if it is bad practice or not?
Here is a sample - line with *next-- = rem + 'A'; is one I am questioning if ok???
#include <stdio.h> /* printf */
#include <string.h> /* strlen, strcpy */
#include <stdlib.h> /* malloc/free */
#include <math.h> /* pow */
/* AAAAA (or whatever length) = 0, to ZZZZZ. base 26 numbering system */
static void getNextString(const char* prev, char* next) {
int count = 0;
char tmpch = 0;
int length = strlen(prev);
int i = 0;
while((tmpch = *prev++) != 0) {
count += (tmpch - 'A') * (int)pow(26.0, length - i - 1);
++i;
}
/* assume all strings are uppercase eg AAAAA */
++count;
/*if count above ZZZ... then reset to AAA... */
if( count >= (int)pow(26.0, length))
count = 0;
next += (length-1); /* seek to last char in string */
while(i-- > 0) {
int rem = count % 26;
count /= 26;
*next-- = rem + 'A'; /*pntr positioned on 1 before array on last iteration - is OK? */
}
}
int main(int argc, char* argv[])
{
int buffsize = 5;
char* buff = (char*)malloc(buffsize+1);
strcpy(buff, "AAAAA");
int iterations = 100;
while(--iterations){
getNextString(buff, buff);
printf("iteration: %d buffer: %s\n", iterations, buff);
}
free(buff);
return 0;
}
According to the following C-FAQ question\answer, and I quote:
Pointer arithmetic is defined only as long as the pointer points
within the same allocated block of memory, or to the imaginary
``terminating'' element one past it; otherwise, the behavior is
undefined, even if the pointer is not dereferenced.
So my answer would be no, it is not OK to iterate before the beginning of an array.
There are references to the C standards as well:
K&R2 Sec. 5.3 p. 100, Sec. 5.4 pp. 102-3, Sec. A7.7 pp.
205-6
ISO Sec. 6.3.6 (C89) or 6.5.6/8 (C99)
Rationale Sec. 3.2.2.3
As long as you don't try to read or write from that address, it won't cause a violation. This is becuase the value in a ptr is just another number.
The only reason your code is working is that your length happens to be less than or equal to the initial value in i.
I personally would not want to rely on this, since I know I'd forget about that particular condition, and I'd make some modification that broke it. So while it technically works, it's not really a good idea.
[expr.add], ¶5
If both the pointer operand and the result point to elements of the same array object, or one past
the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is
undefined.
So it's UB, since the result do not point to any valid element of the array.
comment, acctually: (to FelixCQ's answer)
I could understand why obtaining an Out-of-range pointer in a loop could be dangerous because of possible loop unrolling and out-of-order evaluation, so that the pointer could get derefferenced before the terminating condition is evaluated, as in this simple example:
for (char* tmp = s+len; tmp >= s; tmp--) sum += *tmp;
However, if this is the reason for UB, then
for (int i = len; i >= 0; i--) sum += s[i];
has exactly the same problem! Or am I missing something?
I am new to C, so forgive me if this question is trivial. I am trying to reverse a string, in
my case the letters a,b,c,d. I place the characters in a char* array, and declare a buffer
which will hold the characters in the opposite order, d,c,b,a. I achieve this result using
pointer arithmetic, but to my understanding each element in a char* array is 4 bytes, so when I do the following: buffer[i] = *(char**)letters + 4; I am supposed to be pointing at the
second element in the array. Instead of pointing to the second element, it points to the third. After further examination I figured that if I increment the base pointer by two
each time I would get the desired results. Does this mean that each element in the array
is two bytes instead of 4? Here is the rest of my code:
#include <stdio.h>
int main(void)
{
char *letters[] = {"a","b","c","d"};
char *buffer[4];
int i, add = 6;
for( i = 0 ; i < 4 ; i++ )
{
buffer[i] = *(char**)letters + add;
add -= 2;
}
printf("The alphabet: ");
for(i = 0; i < 4; i++)
{
printf("%s",letters[i]);
}
printf("\n");
printf("The alphabet in reverse: ");
for(i = 0; i < 4; i++)
{
printf("%s",buffer[i]);
}
printf("\n");
}
You're not making an array of characters: you're making an array of character strings -- i.e., an array of pointers to arrays of characters. I am not going to rewrite the whole program for you of course, but I'll start out with two alternative possible correct declarations for your main data structure:
char letters[] = {'a','b','c','d, 0};
char * letters = "abcd";
Either of these declares an array of five characters: a, b, c, d followed by 0, the traditional ending for a character string in C.
Another thing: rather than making assumptions about the size of things, use the language to tell you. For instance:
char *my_array[] = { "foo" , "bar" , "baz" , "bat" , } ;
// the size of an element of my_array
size_t my_array_element_size = sizeof(my_array[0]) ;
size_t alt_element_size = size(*my_array) ; // arrays are pointers under the hood
// the number of elements in my_array
size_t my_array_element_cnt = sizeof(my_array) / sizeof(*myarray ;
// the size of a char
size_t char_size = sizeof(*(my_array[0])) ; // size of a char
Another thing: understand your data structures (as noted above). You talk about chars, but your data structures are talking about strings. Your declarations:
char *letters[] = {"a","b","c","d"};
char *buffer[4];
get parsed as follows:
letters is an array of pointers to char (which happen to be nul-terminated C-style strings), and it's initialized with 4 elements.
Like letters, buffer is an array of 4 pointers to char, but uninitialized.
You are not actually dealing individual chars anywhere, even in the printf() statements: the %s specifier says the argument is a nul-terminated string. Rather, you're dealing with strings (aka pointers to char) and arrays of the same.
An easier way:
#include <stdio.h>
int main(void)
{
char *letters[] = { "a" , "b" , "c" , "d" , } ;
size_t letter_cnt = size(letters)/sizeof(*letters) ;
char *buffer[sizeof(letters)/sizeof(*letters)] ;
for ( int i=0 , j=letter_cnt ; i < letter_cnt ; ++i )
{
buffer[--j] = letters[i] ;
}
printf("The alphabet: ");
for( int i = 0 ; i < letter_cnt ; ++i )
{
printf("%s",letters[i]);
}
printf("\n");
printf("The alphabet in reverse: ");
for( int i=0 ; i < letter_cnt ; i++ )
{
printf("%s",buffer[i]);
}
printf("\n");
}
BTW, is this homework?
This is a case of operator precedence. When you use buffer[i] = *(char**)letters + add;, the * before the cast is performed before the +, making this code equivalent to (*(char**)letters) + add;. The first part is equivalent to the address of the first element in your array, the string "a". Since using string constant automatically adds a null byte, this points to 'a\0'. It happens that the compiler placed all four strings immediately after each other in memory, so if you go past the end of that string you flow into the next. When you add to the pointer, you are moving through this character array: 'a\0b\0c\0d\0'. Notice that each character is 2 bytes after the last. Since this is only true because the compiler placed the 4 strings directly after each other, you should never depend on it (it won't even work if you tried to re-reverse your other string). Instead, you need to put in parentheses to make sure the addition happens before the dereference, and use the 4 byte pointer size. (Of course, as pointed out by Nicholas, you shouldn't assume the size of anything. Use sizeof to get the size of a pointer instead.)
buffer[i] = *((char**)letters + add);
char *letters[] = {"a","b","c","d"};
I think you didn't get the pointer arithmetic correctly. letters is an array of pointers and when incremented by 1 makes to go to next row.
letters + 1 ; // Go to starting location of 2 row, i.e., &"b"
char *letters[] = { "abc" , "def" } ;
(letters + 1) ; // Point to the second row's first element, i.e., &"d"
*((*letters) + 1) ; // Get the second element of the first row. i.e., "b"