C - Ways to count array length - arrays

I need the length of an array. One way works perfectly, one gives the wrong answer, and one doesn't compile.
This doesn't compile:
size_t len = sizeof(array) / sizeof(array[0]);
This counts only first 4 letters:
size_t len = sizeof(array) / sizeof(char);
And len = 12 works.
I really don't understand this so some hint is greatly appreciated.
const char array[] = {'t', 'h', 'i', 's', 'i', 's', 'm', 'y', 't', 'e', 'x', 't', '\0'};
void count_chars(const char *array, unsigned int *counts)
{
size_t len = 12;
for(size_t i = 0; i < len; i++){
counts[(int)array[i]]++;
}
}

You cant determine the size of the passed array inside function. You need to pass size as an additional parameter.
const char array[] = {'t', 'h', 'i', 's', 'i', 's', 'm', 'y', 't', 'e', 'x', 't', 0};
void count_chars(const char *arr, unsigned int *counts, size_t size)
{
for(size_t i = 0; i < size; i++)
counts[(unsigned)arr[i]]++;
}
int main(void)
{
int cnt[sizeof(array[0]) * (1 << CHAR_BIT)];
count_chars(array, cnt, sizeof(array) / sizeof(array[0]));
}
You need to cast to unsigned (not int) because char values can be negative.

What you are trying to do is actually impossible in C. The general rule of thumb is to calculate the length of the array in the function where the array is declared and pass it to the function. This is due to the fact that C doesn't pass the entire array when calling a function but rather just the base address as a pointer variable. To breakdown your approaches and the reason they do/don't work are:
size_t len = sizeof(array) / sizeof(array[0]);
This the commonly accepted approach but the prerequisite is that array must be declared in the same scope not be a pointer.
size_t len = sizeof(array) / sizeof(char);
As array is pointer a type variable and therefore has the size 4(atleast on 32-bit machines) dividing by sizeof(char) is 1 resulting in the answer 4
size_t len = 12;
This works as it's hard coded.
An easy solution in your case could be use:
size_t len = strlen(array)
as mentioned assuming you can guarantee that the last element will be 0 or '\0'. In this situation you could also simply modify the looping condition to:
for(int i = 0; array[i] != 0; i++) {
...
}
Hope I could clarify your doubt

size_t len = sizeof(array) / sizeof(array[0]);
This is general approach for getting the length of an array. However, this will not work inside count_chars function because array is defined as local variable (a pointer) inside the API. And if it is the case, the result will be 13 (not 12 as you mentioned) because it count also the \0 at the end.
For string of characters, it is possible to use strlen. As in the question, you expected result = 12 so this might be your right solution. However, this will not work if there is some \0 value in the middle because it will find first string terminator (\0).

In C if you want to get length of Null Terminated Strings you have to check for NULL \0 and count characters.
Check here how strlen method works.
//Custom Strlen function.
size_t my_strlen(const char *str)
{
register const char *s;
for (s = str; *s; ++s);
return(s - str);
}
Strlen Source
To count length of Arrays (General) like Int,Float,Double you can use below method.
size_t int_arr_len = sizeof(int_arr) / sizeof(int_arr[0]);
size_t float_arr_len = sizeof(float_arr) / sizeof(float_arr[0]);
Full Source Code below
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char char_arr[] = {'t', 'h', 'i', 's', 'i', 's', 'm', 'y', 't', 'e', 'x', 't', 0}; // `\0` Null Terminated.
const int int_arr[] = {10, 20, 30, 40, 50};
const float float_arr[] = {1.5f, 2.5f, 3.5f, 4.5f, 5.5f};
//Custom Strlen function.
size_t my_strlen(const char *str)
{
register const char *s;
for (s = str; *s; ++s);
return(s - str);
}
int main()
{
//Array length for Strings(Char array. Null Terminated. `\0`)
size_t char_arr_len1 = strlen(char_arr);
size_t char_arr_len2 = my_strlen(char_arr);
//Array length for General arrays like Int,Float,Double...etc
size_t int_arr_len = sizeof(int_arr) / sizeof(int_arr[0]);
size_t float_arr_len = sizeof(float_arr) / sizeof(float_arr[0]);
//Print length of arrays.
printf("char_arr_len1: %zu\n", char_arr_len1);
printf("char_arr_len2: %zu\n", char_arr_len2);
printf("int_arr_len: %zu\n", int_arr_len);
printf("float_arr_len: %zu\n", float_arr_len);
return 0;
}

Related

strlen() crashes when I call it

I am trying to write a simple piece of code that merges two strings together in even and odd indexes.
This is the code
void two_strings(char a[], char b[]) {
int counta = 0, countb = 0;
int lena = strlen(a);
int lenb = strlen(b);
int lenab = lena + lenb;
char ans[lenab];
for(int i = 0; i<strlen(ans); i++) {
if(i%2 == 0) {
ans[i] = a[counta];
counta++;
}
else {
ans[i] = b[countb];
countb++;
}
}
printf("%s\n", ans);
}
This is the main:
int main() {
char a[] = "hello";
char b[] = "bye";
two_strings(a, b);
return 0;
}
I have compiled it with -Wall and didn't get any warnings or errors, and I have tried it also with long instead of int just to check if that was the issue. when I run the code it doesn't get past the first strlen(a)
Strings in C are defined as a sequence of non-null bytes followed by a terminating null byte ('\0').
The following are equivalent strings
char one[] = "hello";
char two[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
Both of these would have a string length of 5, and occupy 6 bytes of memory.
String handling functions in the Standard Library expect this null-terminating byte, and you will invoke Undefined Behavior by passing a non-null-terminated array to them. strlen and printf (with %s) are examples of these kinds of functions.
In your two_strings function you are not allocating enough memory to store the null-terminating byte. You also make no attempt to place this null-terminating byte in the array.
Allocate an additional byte for the null-terminating byte, and do not attempt to take the string length of an uninitialized array.
void two_strings(char a[], char b[]) {
/* ... */
size_t length = strlen(a) + strlen(b);
char string[length + 1];
for (size_t i = 0; i < length; i++) {
/* ... */
}
string[length] = '\0';
/* ... */
}
Also note that size_t is the correct type to use when dealing with memory indexing, and is the type returned by strlen.
As for your algorithm, in the event where your input strings differ in length you will attempt to continue indexing one of the strings after you have already reached its end.
You will either want to: only take the smaller string's length of characters from the larger string, stopping when the smaller string has been exhausted; or, append the remaining characters of the larger string to the result after the smaller string has been exhausted.
A quick example of the second approach:
#include <stdio.h>
#include <string.h>
void zip_strings(const char *a, const char *b) {
size_t combined_length = strlen(a) + strlen(b);
char joined_string[combined_length + 1];
for (size_t i = 0; i < combined_length; i++) {
const char **src = i & 1 ? &b : &a;
if (!**src)
src = &a;
if (!**src)
src = &b;
joined_string[i] = *((*src)++);
}
joined_string[combined_length] = '\0';
puts(joined_string);
}
int main(int argc, char **argv) {
if (argc > 2)
zip_strings(argv[1], argv[2]);
}
./a.out hello computer
hceolmlpouter

two strings should be different length but are counted as same length

I'm running into an issue with a pair of strings. Toward the bottom of my first function I test the length of both strings, and even though searchingForLength should be less than half the size of searchedLength, they are the same "length". What is going on here?
Here's the code:
#include <stdio.h>
#include <stdbool.h>
bool findString(const char searched[], const char searchingFor[]) {
int i, j, k = 0, searchedLength = sizeof(searched)/sizeof(searched[0]), searchingForLength = sizeof(searchingFor)/sizeof(searchingFor[0]);
bool in = false;
for (i = 0; i < searchedLength; i++) {
for (j = 0; j < searchingForLength; j++) {
if (searched[i] == searchingFor[j]) {
k++;
if (k == searchingForLength) {
in = true;
}
}
}
}
printf("%d\n", k);
printf("%d\n",searchingForLength);
printf("%d\n",searchedLength);
if (in == true) {
printf("Yes\n");
}
else {
printf("No\n");
}
return in;
}
int main (void) {
const char searched[] = { 'I', ' ', 'l', 'i', 'k', 'e', ' ', 'p', 'i', 'e' };
const char searchingFor[] = { 'l', 'i', 'k', 'e' };
findString(searched, searchingFor);
return 0;
}
Sizeof is evaluated at compile time, and in this case it will return the size of a pointer (char[] is more or less a char*). You should use strlen instead.
Oh and as it has been mentioned, you strings are not zero-terminated, so that won't really work either. You should define your strings as
const char blah[] = "whee"
The sizeof is an operator and it gives the size of the type of it's argument, which is not the length of a string.
For arrays it gives the size of the array in bytes, to calculate the length of a string you need strlen(), but none of your arrays are strings, and hence you can't use strlen(), they are not strings in a c string sense.
A string in c, is a sequence of non-nul bytes followed by a nul byte, your arrays don't have a terminating nul, so the str* functions can't handle them properly.
A simple implementation of strlen() would be
size_t strlen(const char *string)
{
size_t length;
length = 0;
while (*string++ != '\0')
length++;
return length;
}
as you can see, if there is no '\0' or nul byte1 in the data, the function will keep iterating beyond the end of the string, what happens after that is undefined.
1They are the same and their value is 0

an array of char pointers in c

I want to use an array of char pointers where each pointer in the array is pointing to a char in another char array, therefore, I would be able to print the char array through the pointers.
char city[14] = {'D', 'u', 'b', 'a', 'i'};
char *charPointers[100] = {0};
for(size_t i = 0;city[i] != '\0'; i++)
charPointers[i] = &city[i];
printf("\ncity = ");
for(size_t i = 0; *charPointers != 0; i++)
//printf("%c", *(charPointers[i]));
putchar(*charPointers[i]);
Is charPointers an array of pointers or simply a string ?
If it's a string, then how can I use an array of pointers such that each pointer is pointing to a char?
What's an elegant way to achieve what I want? (preferably using pointer arithmetic)
charPointers is an array of pointers; it is categorically not simply a string.
Since it isn't a string, your second question is moot.
Your loop condition is incorrect; you need to write:
for (size_t i = 0; charPointers[i] != 0; i++)
//printf("%c", *(charPointers[i]));
putchar(*charPointers[i]);
putchar('\n');
You're testing whether the first pointer is null; it isn't. You need to check the current pointer on each iteration. The loop below might help you understand what's going on, too:
for (size_t i = 0; charPointers[i] != 0; i++)
printf("%zd [%s]\n", i, charPointers[i]);
This code:
#include <stdio.h>
int main(void)
{
char city[14] = {'D', 'u', 'b', 'a', 'i'};
char *charPointers[100] = {0};
for(size_t i = 0;city[i] != '\0'; i++)
charPointers[i] = &city[i];
printf("city = ");
for (size_t i = 0; charPointers[i] != 0; i++)
putchar(*charPointers[i]);
putchar('\n');
for (size_t i = 0; charPointers[i] != 0; i++)
printf("%zd [%s]\n", i, charPointers[i]);
return 0;
}
produces this output:
city = Dubai
0 [Dubai]
1 [ubai]
2 [bai]
3 [ai]
4 [i]
charPointer is an array of pointers to char. A pointer to an array of char would be char (*p)[100];.
Your code is near correct, here is the not-segfaulting version :
char city[14] = {'D', 'u', 'b', 'a', 'i', '\0'};
char* charPointers[100] = {0};
size_t i =0;
for(i = 0; city[i] != '\0'; i++)
charPointers[i] = city + i;
charPointers[i] = city + i; // Don't forget to add the \0 at the end !
printf("\ncity = ");
for(i = 0; *charPointers[i] != '\0'; i++)
printf("%c", *charPointers[i]);
I don't really know what you want to do, but the code above is storing a pointer to each character of the string city in each element of charPointers.
However, if you want to store a pointer to existing string in charPointers (for instance, each element of charPointers points to a city name), here would be the correct code:
char* cityNames[NB_CITY];
char* city = "Dubai";
cityNames[0] = city;
printf("%s\n", cityNames[0]); // gives "Dubai"
charPointers is clearly an array of pointers to characters. The array city is a string (as pointed out in a comment) since you've specified a length of 14 but only provided 5 actual characters. The rest are set to zero which will terminate the string.
A much clearer way to get the same result would be:
const char *city = "Dubai";
Your loop over *charPointers is strange, since it treats *charPointers as a character, when it's really a pointer.
Perhaps you meant:
for(size_t i = 0; charPointers[i] != NULL; ++i)
printf("%s\n", charPointers[i]);
I want to use an array of char pointers where each pointer in the array is pointing to a char in another char array
Why? There is never a reason why you would want to do this, in real world programming.
therefore, I would be able to print the char array through the pointers
Indeed. That's handy if your program is too fast and too effective.
Is charPointers an array of pointers or simply a string?
It's an array of pointers.
What's an elegant way to achieve what I want?
There is no elegant way to "use an array of char pointers where each pointer in the array is pointing to a char in another char array". This is obfuscation and it fills no purpose except making your code slow and unreadable.
Sane, elegant code would look like this:
const char city [] = {'D', 'u', 'b', 'a', 'i', '\0'};
printf("City = ");
print_str(city);
...
void print_str (const char* str)
{
while(*str != '\0')
{
putchar(*str);
str++;
}
}

How to get char array size in this case?

I'm with this doubt: how to get the size of a char array in this case:
#include<stdio.h>
void f(char * x)
{
printf("Size %d\n", sizeof(x)/sizeof(char));
}
main()
{
char x[5] = {'a', 'e', 'i', 'o', 'u'};
f(&x[0]);
}
Contrary to my expectations, I'm receiving 8 rather than 5 or even 6. What is wrong here?
Thanks!
sizeof(x) in your code will return the size of pointer char *x and not the size of the char array that x is pointing on
and the size of pointer in your 64-bits system is 8. and for 32-bits system the size of pointer is 4
Here, sizeof() is returning the size of the pointer, not the size of the original array.
The only way for f() to know the size of the array pointed to by the char* is for it to be told by the caller:
void f(char * x, size_t size)
{
...
}
main()
{
char x[5] = {'a', 'e', 'i', 'o', 'u'};
f(x, sizeof(x) / sizeof(x[0]));
}
You can not. sizeof returns the size of a pointer.
Store the size of your array in a variable and pass it too.
I prefer this:
void f(char *x, int size)
{
// ...
}
main()
{
char x[5] = {'a', 'e', 'i', 'o', 'u'};
f(x, 5);
}
sizeof(x) gives you size of the char pointer not the size of the array. char * is a pointer to a char. If you dochar a = 'A'; f(&a); it is still valid. char * is not designed to point to only char arrays, so sizeof(x) returns size of the pointer and not what it is pointing at.
You get it like this
void f(char * x, int size_of_array)
{
printf("Size %d\n", size_of_array);
}
main()
{
char x[5] = {'a', 'e', 'i', 'o', 'u'};
f(&x[0], 5);
}
Once you pass an array it decays into a pointer of that type, and you loose the ability to get the size of the array via the sizeof macro. You need to pass the number of elements. If your array is of numeric type you can always pass the size of an array as the first element:
void f(char * x)
{
printf("Size %d\n", x[0]);
}
main()
{
char x[6] = {6, 'a', 'e', 'i', 'o', 'u'};
f(&x[0]);
}
But of course in this case there's extra overhead to updating that element to make sure it matches what you expect.

Compare char arrays

If I had an array of characters for example:
A = [w, o, r, n, g, , w, o, r, d]
And another array for example:
B = [c, o, r, r, e, c, t, , w, o, r, d, .]
I need to compare the words in array A (which are separated by a blank space) to array B and if any of the words in the first array exist in the second array, then that word should be printed. So for example, since "word" exists in the first array and in the second array, then "word" should be printed out.
How do I go about this?
Let's see how I would do it:
You will need a function that, given an array of char, splits it in an array of words (and put them in C strings, NUL terminated please :-) ). I would put the length of this array and the array in a struct
struct WordCollection
{
size_t NumWords;
char **Words;
}
Now... How to do this function?
Let's say we "cheat" a little and decide that our arrays A and B are NUL terminated (or if they are . terminated like B, then you replace the . with a NUL). Now, this being C, you should first count the number of spaces in the string, allocate an array of char* (WordCollection::Words) big enough to contain n + 1 char* (and put this n + 1 in WordCollection::NumWords) and using strtok "tokenize" the string and put the words in the array you created.
Then you should (could) split the A and B array in words using this function. You'll obtain two WordCollection, A1 and B1.
To make it quicker, I would qsort B1.
Then for each word in A1 you bsearch it in B1 (it isn't a bad word... It means Binary Search, and it's a quick method of searching something in an ordered array)
Done :-)
I'll add that, if this is the first time you use bsearch and qsort, it's better you look at the samples you can find around. Their syntax can be "tricky".
Now... I know you won't look at the code :-) so I'll put it here
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct WordCollection
{
size_t NumWords;
char **Words;
};
void splitWord(char *str, struct WordCollection *wc)
{
char *c;
char **currentWord;
c = str;
wc->NumWords = 1;
while (*c != '.')
{
if (*c == ' ')
{
wc->NumWords++;
}
c++;
}
*c = '\0';
wc->Words = (char**)malloc(wc->NumWords * sizeof(char*));
c = strtok(str, " ");
currentWord = wc->Words;
while (c)
{
*currentWord = c;
currentWord++;
c = strtok(NULL, " ");
}
}
int myComp(const void *p1, const void *p2)
{
return strcmp(*(const char**)p1, *(const char**)p2);
}
int main(void)
{
char a[] = { 'w', 'o', 'r', 'n', 'g', ' ', 'w', 'o', 'r', 'd', '.' };
char b[] = { 'c', 'o', 'r', 'r', 'e', 'c', 't', ' ', 'w', 'o', 'r', 'd', '.' };
struct WordCollection a1, b1;
struct WordCollection *pSmaller, *pBigger;
size_t i;
splitWord(a, &a1);
splitWord(b, &b1);
if (a1.NumWords <= b1.NumWords)
{
pSmaller = &a1;
pBigger = &b1;
}
else
{
pSmaller = &b1;
pBigger = &a1;
}
qsort(pBigger->Words, pBigger->NumWords, sizeof(char*), myComp);
for (i = 0; i < pSmaller->NumWords; i++)
{
void *res = bsearch(&pSmaller->Words[i], pBigger->Words, pBigger->NumWords, sizeof(char*), myComp);
if (res)
{
printf("Found: %s", pSmaller->Words[i]);
}
}
free(a1.Words);
free(b1.Words);
return 0;
}
And on ideone
Basically you need to somehow separate the words, and then iterate through the combinations. There are a hundred ways to do this -- it simply requires programming.
You can also do it like that:
Insert all words from set A into set C with suffix 'A'. You will get =>
worngAwordA
Insert all words from set B into set C with suffix 'B'. You will get =>
correctBwordB
Run sorting algo on set C such as qsort. You will get =>
correctBwordAwordBworngA
Loop in set C until it's size-1. Compare word[i] with word[i+1] - if they match except the last letter - you found duplicate and you can print it out.
I don't know about this algorithm complexity, but it clearly should be faster than just brute-force scan of all words combinations :-)

Resources