Count characters in an array of character strings? - c

Given an array of character strings such as...
char *example[] = {"s", "ss", "sss"};
How can I write a function to count the total number of chars in the array including the terminating characters, without using the standard library for strlen() etc.
Follows is my attempt
int countChars(char *array[], int len)
{
int total = 0, count = 0;
for (int i = 0; i < len; i++)
{
if (array[i] != NULL)
{
while (*array[i] != '\0') {
count++;
}
count++;
}
total += count;
}
return total;
}
An explanation on how char *array[] actually works for access wold be appreciated. I believe that it is supposed to be an array of pointers to strings.

You have to increment the index to consider each of the character.
Something like this:-
for (int i = 0; i < len; i++)
{
if (array[i] != NULL)
{
int j=0,count=0;
while (array[i][j++] != '\0') {
count++;
}
total += count;
}
}
Also reset the count or add to total at the end of all the calculation.
As an answer to your second question:-
char* array[] is basically denoting an array pointers each pointing
to the string literals with which you initialized it.
So once you use array[i] you should now think that it is nothing
other than a pointer to a string literal.

You need to reinitialize the variable count inside the for loop for each processed string and to increase the expression *array[i] inside the while loop.
Also it is better when the function has the return type size_t (size_t is the type that is returned by the standard C function strlen and by the operator sizeof)
The function can look as it is shown in the demonstrative program.
#include <stdio.h>
size_t countChars( const char *array[], size_t n )
{
size_t count = 0;
while ( n-- )
{
if ( array[n] )
{
size_t i = 0;
do { ++count; } while ( array[n][i++] );
}
}
return count;
}
int main(void)
{
const char * example[] = { "s", "ss", "sss" };
printf( "%zu\n", countChars( example, sizeof( example ) / sizeof( *example ) ) );
return 0;
}
The program output is
9
Each element of this array
char *example[] = {"s", "ss", "sss"};
has type char * and is a pointer to the first character of the corresponding string literal.

Since your array contains string constants you should declare it with const:
const char *example[3];
Without const the compiler will not warn you if you try to assign a character to example[i][j]. For the same reason the formal parameter should also be declared with const.
For a pure function with no side effects it is better to name it so that it reflects the result. Therefor I would use charCount instead of countChars (or maybe totalLength). The focus should be on a noun (namely count or length).
Here is my solution:
#include <stdio.h>
#define LEN(a) (sizeof (a) / sizeof (a)[0])
static int CharCount(const char *strings[], int len)
{
int result, i, j;
result = 0;
for (i = 0; i < len; i++) {
j = 0;
while (strings[i][j] != '\0') {
result++;
j++;
}
}
return result;
}
int main(void)
{
const char *strings[] = { "s", "ss", "sss" };
printf("character count: %d\n", CharCount(strings, LEN(strings)));
}
The length macro LEN is very convenient and is the least error prone way to handle array lengths.

Yes char *array[] = {"aa", "bb", "cc"} is an array of pointers to strings.
array[0] points to "aa"
array[1] points to "bb"
array[2] points to "cc"
You probably want this:
int countChars(char *array[], int len)
{
int count = 0;
for (int arrayindex = 0; arrayindex < len; arrayindex++)
{
const char *stringptr = array[arrayindex];
// stringptr will point successively
// to "s", to "ss" and to "sss"
while (*stringptr++)
count++; // increment count until NUL character encountered
count++; // one more for NUL character
}
return count;
}
int main() {
char *example[] = { "s", "ss", "sss" };
int x = countChars(example, 3); // x contains 9 after the call to countChars
// that is 2 + 3 + 4
}
Instead of hard coding 3 you could use sizeof(example) / sizeof(example[0]).

Related

How to initialise new string in loop in C without malloc

I'm trying to instantiate a new string every iteration of a loop. What I tried was this:
int main(void) {
char *strs[10];
for (int i = 0; i < 10; i++) {
char str[10] = "";
char c = '0' + i;
strncat(str, &c, 1);
strs[i] = str;
}
for (int i = 0; i < 10; i++) {
printf("%s\n", strs[i]);
}
}
However, this prints all 9's, since C has conveniently decided that each iteration it would use the same address. I know that the following works, but just wanted to ask if it is possible to avoid malloc.
int main(void) {
char *strs[10];
for (int i = 0; i < 10; i++) {
char *str = malloc(sizeof(char) * 10);
char c = '0' + i;
strncat(str, &c, 1);
strs[i] = str;
}
for (int i = 0; i < 10; i++) {
printf("%s\n", strs[i]);
}
}
I am also interested in instantiating structs the same way without malloc. Is this possible?
A straightforward approach is to declare a two dimensional array like for example
char strs[10][2] = { "" };
for (int i = 0; i < 10; i++) {
strs[i][0] = '0' + i;
}
Here is a demonstration program
#include <stdio.h>
int main( void )
{
enum { N = 10 };
char strs[N][2] = { "" };
for ( int i = 0; i < N; i++ )
{
strs[i][0] = '0' + i;
}
for ( int i = 0; i < N; i++ )
{
printf( "%s ", strs[i] );
}
putchar( '\n' );
}
The program output is
0 1 2 3 4 5 6 7 8 9
Pay attention to that your second program has undefined behavior
char *str = malloc(sizeof(char) * 10);
char c = '0' + i;
strncat(str, &c, 1);
strs[i] = str;
The dynamically allocated array is not initialized. So the call of strncat invokes undefined behavior.
And in the both your programs this call strncat(str, &c, 1); does not build a string. So this call printf("%s\n", strs[i]);again invokes undefined behavior.
Regardless of data type, an object declared at block scope without storage class specifier static* has automatic storage duration. Its lifetime ends when execution of the innermost block containing its declaration terminates. Attempting to access such an object outside its lifetime produces undefined behavior.
If you want an object whose lifetime starts after the beginning of program execution and extends beyond the termination of the innermost block containing the start point, then dynamic allocation is your only choice.
* with static, the object has static storage duration -- the whole run of the program. You can access these via pointer from outside the scope of their identifiers, but for each such declaration there is only object serving the whole execution of the program.
"just wanted to ask if it is possible to avoid malloc."
Yes. The following makes use of Variable Length Arrays, and a function to do this without using calloc or malloc.
Running from the command prompt for example, enter:
your_program_name 10 5<return> to create an array of 10 elements each having room for 4 char plus a terminating null.
void populate_strs(int num, int longest, char sArr[num][longest])
{
for(int i=0;i<num; i++)
{
char c[2] = {0};
c[0] = '0' + (char)i;
c[1] = 0;//null terminate string
strncat(sArr[i], c, 1);//do not need & for string
}
}
int main(int argc, char *argv[])
{
if(argc != 3) printf("Usage error...");
int num_str = atoi(argv[1]);
int max_len = atoi(argv[2]);
char strs[num_str][max_len];
memset(strs, 0, sizeof strs);
populate_strs(num_str, max_len, strs);
for (int i = 0; i < 10; i++) {
printf("%s\n", strs[i]);
}
return 0;
}
And the same is true for an array of struct;
Given this for example:
typdef struct {
int val;
char str;
bool state;
} data_s;
...
int size = 0;
printf("Enter how many array elements of data_s to create.\n");
fscanf(stdin, "%d", &size);
data_s data[size];
memset(data, 0, sizeof data);
//use array of data;

What is the meaning of str[][20]

I just have a function here in C language, Can you please tell me what does str[ ][20] meaning and why do we need it
void printlist(char str[][20], int n) {
int i;
printf("\t*******************************\n");
printf("\tNo.\t\t\tName");
printf("\n\t*****************************\n");
for (i = 0; i < n; i++) {
printf("\t%d \t\t\t%s\n", i + 1, str[i]);
}
}
Thanks in advance
char str[][20], means that you have an unknown number of char arrays of size 20.
The parameter n to the function printlist specifies, how many rows there are in the specified array str.
Example:
int main()
{
char str[][20] = { "Hello", "World" };
printlist(str, sizeof str / 20); // <-- printlist(str, 2);
return 0;
}

C updating string incrementally

I am trying to update string step by step in C. The code i tried is below:
#include <stdlib.h>
#include <stdio.h>
int writech(char **text, char ch) {
**text = ch;
return 1;
}
char *write(int array[], size_t size) {
char *string = (char*)malloc(sizeof(char)*(size+1));
int i, n;
for (i = 0; i < size; ++i) {
n = writech(&string, '0' + array[i]);
string += n;
}
return string;
}
int main() {
int arr[] = { 1, 2, 3, 4, 5 };
char *str = write(arr, sizeof(arr)/sizeof(arr[0]));
printf("%s\n", str);
return 0;
}
Here, write function should update string by calling other function and return updated string at the end. The code compiled and run successfully, though str (at the end of main) is empty after all. Actually, my task is to create string that contain table of some data and return it at the end. Pseudo code for my idea is below:
char *render_table() {
char *table = malloc(sizeof table);
write_header(table);
write_row(table, some_data);
write_row(table, some_data);
write_footer(table)
return table;
}
For implementing this pseudo code I wrote the above code, but not able to update passed string successfully. I know pointers are passed to function as copies, and passed memory of my string (writech(&string) to function, but string not updated still. What am i missing?
P.S. Tweaking with pointers is really struggling for me as beginner in C. What would you suggest?
string is updated. The problem is the pointer string is updated and the information of the beginning of the string is lost. You have to hold the information.
One more point is that terminating null-character must be added to pass the buffer for %s (without specifying length to print).
Also note that casting results of malloc() in C is discouraged.
Try this:
char *write(int array[], size_t size) {
char *string = malloc(sizeof(char)*(size+1));
char *cursor = string;
int i, n;
for (i = 0; i < size; ++i) {
n = writech(&cursor, '0' + array[i]);
cursor += n;
}
writech(&cursor, '\0');
return string;
}
Seems to me that you are making this much more complicated than needed.
Simply do:
for (i = 0; i < size; ++i) {
string[i] = '0' + array[i]);
}
string[i] = '\0';
If for some reason you really want to use the writech function, you can change it to:
void writech(char *text, char ch) {
*text = ch;
}
and call it like:
for (i = 0; i < size; ++i) {
writech(string + i, '0' + array[i]);
}
string[i] = '\0';
but it's really just making a simple task complex.
EDIT due to comment
If you (in your real code) don't know how many chars will be added by a function call, you simply do:
int writeSomethingA(char* str, ... other arguments ...)
{
// update str, e.g. like str[0] = 'a'; str[1] = 'b';
// or strcpy(str, "Some text");
return NumberOfCharAdded;
}
(make similar B and C versions)
and call them like:
char* string malloc(....);
int idx = 0;
idx += writeSomethingA(string + idx, ... other arguments ...);
idx += writeSomethingB(string + idx, ... other arguments ...);
idx += writeSomethingC(string + idx, ... other arguments ...);
string[idx] = '\0';
For starters it is unclear why the function writech
int writech(char **text, char ch) {
**text = ch;
return 1;
}
has the first parameter with the type char ** instead of char *.
The function can be defined like
int writech( char *text, char ch ) {
*text = ch;
return 1;
}
Within the function write the pointer string is being changed in the for loop. So the function returns a pointer that does not point to the beginning of the allocated memory.
Also as you are using the conversion specifier %s to output the character array in main then the array shall contain a string. That is the array shall have contain the terminating zero character '\0'.
The function can be implemented the following way
char * write( const int array[], size_t size ) {
char *string = malloc( size + 1 );
if ( string != NULL )
{
char *p = string;
while ( size-- ) {
p += writech( p, '0' + *array++ );
}
*p = '\0';
}
return string;
}
And you should free the allocated memory before exiting main like
free( str );

How to check if a string is in an array of strings in C?

How to write below code in C? Also: is there any built in function for checking length of an array?
Python Code
x = ['ab', 'bc' , 'cd']
s = 'ab'
if s in x:
//Code
There is no function for checking length of array in C. However, if the array is declared in the same scope as where you want to check, you can do the following
int len = sizeof(x)/sizeof(x[0]);
You have to iterate through x and do strcmp on each element of array x, to check if s is the same as one of the elements of x.
char * x [] = { "ab", "bc", "cd" };
char * s = "ab";
int len = sizeof(x)/sizeof(x[0]);
int i;
for(i = 0; i < len; ++i)
{
if(!strcmp(x[i], s))
{
// Do your stuff
}
}
Something like this??
#include <stdio.h>
#include <string.h>
int main() {
char *x[] = {"ab", "bc", "cd", 0};
char *s = "ab";
int i = 0;
while(x[i]) {
if(strcmp(x[i], s) == 0) {
printf("Gotcha!\n");
break;
}
i++;
}
}
A possible C implementation for Python's in method could be
#include <string.h>
int in(char **arr, int len, char *target) {
int i;
for(i = 0; i < len; i++) {
if(strncmp(arr[i], target, strlen(target)) == 0) {
return 1;
}
}
return 0;
}
int main() {
char *x[3] = { "ab", "bc", "cd" };
char *s = "ab";
if(in(x, 3, s)) {
// code
}
return 0;
}
Note that the use of strncmp instead of strcmp allows for easier comparison of string with different sizes. More about the both of them in their manpage.
There is a function for finding string length. It is strlen from string.h
And then you could use the strcmp from the same header to compare strings, just as the other answers say.

Implementation of strspn( )

The definition of library function strspn is:
size_t strspn(const char *str, const char *chars)
/* Return number of leading characters at the beginning of the string `str`
which are all members of string `chars`. */
e.g. if str is "fecxdy" and chars is "abcdef" then the function would return 3, since f, e and c all appear somewhere in chars, giving 3 leading characters of str, and x is the first character of str which is not a member of chars.
Could someone help me write an implementation of strspn in C. The only library function I am allowed to call from the implementation is strlen?
The basic idea is to step through the string, one character at a time, and test if it's in the character set. If it's not, stop and return the answer. In pseudocode, that would look like:
count = 0
for each character c in str
if c is not in chars
break
count++
return count
The if c is not in chars test can be implemented by iterating through all of the characters of chars and testing if c matches any of the characters. Note that this is not the fastest implementation, since it involves stepping through the chars string for each character in str. A faster implementation would use a lookup table to test if c is not in chars.
I found this question while going over old exams. You weren't allowed to use indexing or any standard functions. Here's my attempt at a solution:
#include <stdio.h>
size_t myStrspn(const char *str1, const char *str2){
size_t i,j;
i=0;
while(*(str1+i)){
j=0;
while(*(str2+j)){
if(*(str1+i) == *(str2+j)){
break; //Found a match.
}
j++;
}
if(!*(str2+j)){
return i; //No match found.
}
i++;
}
return i;
}
void main(){
char s[] = "7803 Elm St.";
int n = 0;
n = myStrspn(s,"1234567890");
printf("The number length is %d. \n",n);
}
Here's the solution from the exam:
#include<stdio.h>
size_t strspn(const char* cs, const char* ct) {
size_t n;
const char* p;
for(n=0; *cs; cs++, n++) {
for(p=ct; *p && *p != *cs; p++)
;
if (!*p)
break;
}
return n;
}
For loops made it much more compact.
I think this should be pretty fast
size_t strspn(const unsigned char *str, const unsigned char *chars){
unsigned char ta[32]={0};
size_t i;
for(i=0;chars[i];++i)
ta[chars[i]>>3]|=0x1<<(chars[i]%8);
for(i=0;((ta[str[i]>>3]>>(str[i]%8))&0x1);++i);
return i;
}
Thanks to others for sanity checks.
A naive implementation of strspn() would iterate on the first string, as long as it finds the corresponding character in the second string:
#include <string.h>
size_t strspn(const char *str, const char *chars) {
size_t i = 0;
while (str[i] && strchr(chars, str[i]))
i++;
return i;
}
Given that you are not allowed to call strchr(), here is a naive native implementation:
size_t strspn(const char *str, const char *chars) {
size_t i, j;
for (i = 0; str[i] != '\0'; i++) {
for (j = 0; chars[j] != str[i]; j++) {
if (chars[j] == '\0')
return i; // char not found, return index so far
}
}
return i; // complete string matches, return length
}
Scanning the second string repeatedly can be costly. Here is an alternative that combines different methods depending on the length of chars, assuming 8-bit bytes:
size_t strspn(const char *str, const char *chars) {
size_t i = 0;
char c = chars[0];
if (c != '\0') { // if second string is empty, return 0
if (chars[1] == '\0') {
// second string has single char, use a simple loop
while (str[i] == c)
i++;
} else {
// second string has more characters, construct a bitmap
unsigned char x, bits[256 / 8] = { 0 };
for (i = 0; (x = chars[i]) != '\0'; i++)
bits[x >> 3] |= 1 << (x & 7);
// iterate while characters are found in the bitmap
for (i = 0; (x = str[i]), (bits[x >> 3] & (1 << (x & 7))); i++)
continue;
}
}
return i;
}
int my_strspn(const char *str1,const char *str2){
int i,k,counter=0;
for(i=0;str1[i]!='\0';i++){
if(counter != i) break;
for(k=0;str2[k]!='\0';k++){
if(str1[i]==str2[k])
counter++;
}
}
return counter;
}
Create a lookup table (a poor man's set) for all possible ASCII chars, and just lookup each character in str. This is worst case O(max(N,M)), where N is the number of characters in str and M is the number of characters in chars.
#include <string.h>
size_t strspn(const char *str, const char *chars) {
int i;
char ch[256] = {0};
for (i = 0; i < strlen(chars); i++) {
ch[chars[i]] = 1;
}
for (i = 0; i < strlen(str); i++) {
if (ch[str[i]] == 0) {
break;
}
}
return i;
}
This could also be solved without using strlen at all, assuming both strings are zero-terminated. The disadvantage of this solution is that one needs 256 bytes of memory for the lookup table.
Without touching a C-compiler for the last couple of years. From the top of my head something like this should work:
int spn = 0;
while(*str++ != '\0')
{
char *hay = chars;
bool match = false;
while(*hay++ != '\0')
{
if(*hay == *str)
{
match = true;
break;
}
}
if(match)
spn++;
else
return spn;
}
return spn;
Well, implementing a standard library for my OS, here is my solution (C++).
KCSTDLIB_API_FUNC(size_t DECL_CALL strspn(const char * str1, const char * str2))
{
size_t count = 0;
auto isin = [&](char c)
{
for (size_t x = 0; str2[x]; x++)
{
if (c == str2[x])
return true;
};
return false;
};
for (; isin(str1[count]); count++);
return count;
}

Resources