How to get char array size in this case? - c

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.

Related

C - Ways to count array length

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;
}

I am getting this error, "error: expected expression before '{' token". I don't know why ? syntax looks fine to me

/*Using structures, write an interactive C program to
generate Grade Card for BCA first semester courses for
20 students of your study centre.*/
#include<stdio.h>
struct Marks
{
char subject[5];
float subject_marks[5];
};
struct GradeCard
{
char name[30];
int roll_num;
struct Marks table;
};
int main()
{
struct GradeCard student;
int i;
//name of student
printf("Enter the name of student: \t");
scanf("%s", &student.name);
//roll number of student
printf("Enter the roll number of student: \t");
scanf("%d", &student.roll_num);
//name of courses
printf("Enter the subjects: \t");
student.table.subject[5] = {'B', 'C', 'D', 'E', 'F'};
//marks in respective courses
for (i = 0; i < 5; i++)
{
scanf("%f", &student.table.subject_marks[i]);
}
//printing all the details
printf("%s\n", student.name);
printf("%d\n", student.roll_num);
for(i = 0; i < 5; i++)
{
printf("%s : %f\n",student.table.subject[i], student.table.subject_marks[i]);
}
}
I have to do this for 20 students. I want to try it with one student first. The error I am getting is this:
error: expected expression before '{' token
student.table.subject[5] = {'B', 'C', 'D', 'E', 'F'};
For this line:
student.table.subject[5] = {'B', 'C', 'D', 'E', 'F'};
I guess that OP thinks that the line assigns values to all the elements of the array student.table.subject[5] in the same way that char subject[5] = {'B', 'C', 'D', 'E', 'F'}; initializes all elements of the array subject[5]. They may look similar, but an assignment is not the same as an initialization.
There are some problems with the assignment attempted above. :-
Problem 1: {'B', 'C', 'D', 'E', 'F'} on the right side of an assignment expression is not a value of any type. It could be turned into a value of type char [5] by changing it into a compound literal. (char [5]){'B', 'C', 'D', 'E', 'F'} is a compound literal of type char [5]; it could also be written as (char []){'B', 'C', 'D', 'E', 'F'} where the number of elements is determined by the number of initializers between the braces. It is an unnamed array object.
Problem 2: In most expressions, a value of an array type is converted into a pointer to the first element of the array and is no longer an lvalue. The left hand operand of the assignment operator = must be an lvalue. Therefore, the left hand operand of the assignment operator cannot be an array.
There are various ways to solve OP's problem. :-
Solution 1: Use memcpy to copy the values from another array:
static const char subjects[5] = {'B', 'C', 'D', 'E', 'F'};
memcpy(student.table.subject, subjects, 5);
or:
memcpy(student.table.subject, (char [5]){'B', 'C', 'D', 'E', 'F'}, 5);
(Note: That makes use of a compound literal containing the source array contents to be copied to the destination.)
or:
memcpy(student.table.subject, "BCDEF", 5);
(Note: "BCDEF" is just being used for convenience there. It has type char [6] including the null terminator, but only the first 5 elements are being copied.)
Solution 2: Use a for loop to copy the values from another array:
static const char subjects[5] = {'B', 'C', 'D', 'E', 'F'};
for (i = 0; i < 5; i++)
{
student.table.subject[i] = subjects[i];
}
or:
for (i = 0; i < 5; i++)
{
student.table.subject[i] = ((char []){''B', 'C', 'D', 'E', 'F'})[i];
}
or:
for (i = 0; i < 5; i++)
{
student.table.subject[i] = "BCDEF"[i];
}
Solution 3: Assign to each element of the array using a linear sequence of statements:
student.table.subject[0] = 'B';
student.table.subject[1] = 'C';
student.table.subject[2] = 'D';
student.table.subject[3] = 'E';
student.table.subject[4] = 'F';
(Note: For a large number of elements, that would get tedious and be an inefficient use of executable memory unless the compiler can optimize it to the equivalent of a memcpy.)

Passing char matrix to C function

I have to work with a given function that is declared like this:
void someFunc (char** characters, int from, int to);
The problem is, i cant find a way to pass a matrix to it, for example:
char matrix[4][4] = { { 'a', 'e' , 'i', 'm'},
{ 'b', 'f' , 'j', 'n'},
{ 'c', 'g' , 'k', 'p'},
{ 'd', 'h' , 'l', 's'} };
someFunc(matrix, 2, 3); //doesnt work
someFunc(&matrix, 2, 3); //doesnt work
The compiler complains, but i cant change the signature of someFunc, so how i can do to pass a char matrix to the function?
AS #IgorTandetnik said
define like this
char* data[]= {matrix[0], matrix[1], matrix[2], matrix[3]};
someFunc(data, 2, 3); // works fine
array of character pointers initialized with the each row of matrix and then passed this as argument
test code:
#include<stdio.h>
void someFunc (char** characters, int from, int to);
char matrix[4][4] = { { 'a', 'e' , 'i', 'm'},
{ 'b', 'f' , 'j', 'n'},
{ 'c', 'g' , 'k', 'p'},
{ 'd', 'h' , 'l', 's'} };
main()
{
char* data[]= {matrix[0], matrix[1], matrix[2], matrix[3]};
someFunc(data, 2, 3);
}
void someFunc (char** c , int from, int to)
{
int i=0,j=0;
for(i=0;i<4;i++)
for(j=0;j<4;j++)
printf("%c\n",c[i][j]); //printf("%c",*(c[i]+j));
}
instead of using an automatic matrix just malloc a pointer to pointer the code goes like this
main(void)
{
int i;
char **ptr = NULL;
ptr = (char**)malloc(sizeof(char) * 4);
for(i = 0 ; i < 4 ; i++)
ptr[i] = (char*)malloc(sizeof(char) * 4);
//initialize your matrix here
someFunc(ptr , 2 , 3);
}
or , if you are ready to modify the function prototype (just a tiny bit) use this one instead void sumFunc(char matrix[][4) , int from , int to) and you won't have to change any thing else
The below code will work. But you may need to access the array using one index instead of two index in the function. When you declare a double index array, the data is not store as a "pointer to pointer". So you may not pass char foo0[ ][ ] using char **foo1.
void someFunc (char* characters)
{
char c = character[0]; // c = 'a'
c = character[4] // c = 'b'
c = character[8] // c = 'c'
c = character[12] // c = 'd'
}
void main(void)
{
char matrix[4][4] = {
{ 'a', 'e' , 'i', 'm'},
{ 'b', 'f' , 'j', 'n'},
{ 'c', 'g' , 'k', 'p'},
{ 'd', 'h' , 'l', 's'} };
someFunc((char*)matrix);
}
An example of char **variable would be:
char *array[]={"this","is","char","pointer"};
Used like:
someFunc(array, 2, 3);
An example of an array of the previous would have to be something like:
char *array[][5] = {
{"this","is","char","element","one"},
{"this","is","char","element","two"},
{"this","is","char","element","three"}};
But that is not what your prototype requires. Use the previous example to see that that does for you.
[EDIT] per your question and my comment, here is how to access the content of an array. (it is random and can be printed in any format you need).
#include <windows.h>
#include <ansi_c.h>
int main(void)
{
char *array[]={"this","is","char","pointer"};
int i,j;
//print in columns
printf("Columns:\n");
for(i=0;i<7; i++)
{
for(j=0;j<4;j++)
{
if(i> strlen(array[j]))
printf(" ");
else
printf("%c", array[j][i]);
}
printf("\n");
}
//print in rows (easier)
printf("\n\nRows:\n");
for(i=0;i<4;i++)
{
printf("%s\n", array[i]);
}
getchar();
return 0;
}
I had a similar experience once and I found out that using char matrixes kinda give some issues ... this is my actual suggestion, I hope you'll understand it. (I know it's late, but maybe it will be to aid for somebody else)
void someFunc(char* matrix, int from, int to){/*function declaration*/}
int main(){
int x = 4; //first matrix's dimension
int y = 4; //second matrix's dimension
char matrix[x*y];
//printing the matrix all in a single row
for(int i=0, i<x, i++)
for(int j=0, j<y, j++)
printf("%c", matrix[i+j*x]);
//it is just way simpler, reduces a ton of complexity, and having a string is much more flexible than having a matrix, especially with chars
return 0
}

string initialization in C

I am writing insertion sort using strings. I have char arrays like:
char array1[4] = {'a', 'b', 'c', '\0'};
char array2[4] = {'b', 'd', 'e', '\0'};
And I need to use this operation:
char string[2];
string[1] = array1;
string[2] = array2;
Is it possible ?
Because in insertion sort I need a string.
This is the insertion code:
char* insertionsort(char* a, int n) {
int k;
for (k = 1; k < n; ++k) {
int key = a[k];
int i = k - 1;
while ((i >= 0) && (key < a[i])) {
a[i + 1] = a[i];
--i;
}
a[i + 1] = key;
}
return a;
}
So I need to write this operation :
char string [2];
string[1] = array1;
string[2] = array2;
Is it possible ?
Short answer: no, it's not. Arrays are not assignable. You can use strcpy to copy the elements from one string to another, but in this case that won't work either -- you've defined string as an array of 2 chars, but you're trying to assign an entire array of chars to each of those.
It's not entirely clear that it's what you want, but one possibility would be:
char *string[2];
string[1] = array1;
string[2] = array2;
In this case, string is an array of two pointers to char, and the assignments set those to point to the first character of each of your previously defined strings.
Since you've tagged this as both C and C++, I'll add a bit about that: this is written as very much C code. If you're actually using C++, you probably want something more like:
std::string[2] = {"abc", "bde"};
Even in C, I'd prefer to initialize and use string constants where they make sense:
char array1[] = "abc";
char array2[] = "bde";
char *string[] = {array1, array2};
Or even just:
char const *string[] = {"abc", "bde"};
char array1[4] = {'a', 'b', 'c', '\0'}; // same as char *array1 = "abc";
char array2[4] = {'b', 'd', 'e', '\0'}; // same as char *array2 = "bde";
char *string [2]; // an array of 'pointers to chars' / array of strings
string[1] = array1; // this will work
string[2] = array2; // this will work
Of course not. Just remember,
char ary[4] = {'a', 'b', 'c', '\0'}; //define an array of char
When you use ary like this:
char string[2];
string[0] = ary;
ary degenerates from the name of an array to a pointer! So, what you do above is assigning a pointer to a char type, and which will lead to a type warning when compiling.
This is very important in C!
And you can fix it like this:
char *string[2]; //an array of pointers to char
string[1] = array1; //correct
string[2] = array2;

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