What is a way in C that someone could find the length of a character array?
I will happily accept pseudo-code, but am not averse to someone writing it out if they'd like to :)
Provided the char array is null terminated,
char chararray[10] = { 0 };
size_t len = strlen(chararray);
If you have an array, then you can find the number of elements in the array by dividing the size of the array in bytes by the size of each element in bytes:
char x[10];
int elements_in_x = sizeof(x) / sizeof(x[0]);
For the specific case of char, since sizeof(char) == 1, sizeof(x) will yield the same result.
If you only have a pointer to an array, then there's no way to find the number of elements in the pointed-to array. You have to keep track of that yourself. For example, given:
char x[10];
char* pointer_to_x = x;
there is no way to tell from just pointer_to_x that it points to an array of 10 elements. You have to keep track of that information yourself.
There are numerous ways to do that: you can either store the number of elements in a variable or you can encode the contents of the array such that you can get its size somehow by analyzing its contents (this is effectively what null-terminated strings do: they place a '\0' character at the end of the string so that you know when the string ends).
Although the earlier answers are OK, here's my contribution.
//returns the size of a character array using a pointer to the first element of the character array
int size(char *ptr)
{
//variable used to access the subsequent array elements.
int offset = 0;
//variable that counts the number of elements in your array
int count = 0;
//While loop that tests whether the end of the array has been reached
while (*(ptr + offset) != '\0')
{
//increment the count variable
++count;
//advance to the next element of the array
++offset;
}
//return the size of the array
return count;
}
In your main function, you call the size function by passing the address of the first element of your array.
For example:
char myArray[] = {'h', 'e', 'l', 'l', 'o'};
printf("The size of my character array is: %d\n", size(&myArray[0]));
You can use strlen
strlen(urarray);
You can code it yourself so you understand how it works
size_t my_strlen(const char *str)
{
size_t i;
for (i = 0; str[i]; i++);
return i;
}
if you want the size of the array then you use sizeof
char urarray[255];
printf("%zu", sizeof(urarray));
If you want the length of the character array use sizeof(array)/sizeof(array[0]), if you want the length of the string use strlen(array).
There is also a compact form for that, if you do not want to rely on strlen. Assuming that the character array you are considering is "msg":
unsigned int len=0;
while(*(msg+len) ) len++;
using sizeof()
char h[] = "hello";
printf("%d\n",sizeof(h)-1); //Output = 5
using string.h
#include <string.h>
char h[] = "hello";
printf("%d\n",strlen(h)); //Output = 5
using function (strlen implementation)
int strsize(const char* str);
int main(){
char h[] = "hello";
printf("%d\n",strsize(h)); //Output = 5
return 0;
}
int strsize(const char* str){
return (*str) ? strsize(++str) + 1 : 0;
}
You can use this function:
int arraySize(char array[])
{
int cont = 0;
for (int i = 0; array[i] != 0; i++)
cont++;
return cont;
}
By saying "Character array" you mean a string? Like "hello" or "hahaha this is a string of characters"..
Anyway, use strlen(). Read a bit about it, there's plenty of info about it, like here.
Well, 11 years later, I run into this issue with a college assignment. The solution I found, worked without having to alter the function signatures that the assignment was asking for.
In my case, I had to make a function that returns the item index if the item existed or depending on if the itemPrefix (e.g. 'B' for Banana) already exists or not in the character array itemPrefixes to avoid passing duplicate prefixes.
So, I had to use a for loop (or while loop). The problem was that the assignment had given me specific signatures for each function and for that specific function it didn't allow me to pass the count variable that was on the main() function as an argument.
I had to improvise.
Both the ways mentioned above didn't work. strlen() didn't work as intended since there was not a '\0' end character that strings have. The sizeof() method also didn't work, because it returned the size of the pointer of the character array that was passed in as an argument instead of the number of elements.
So, this is the function I came up with. A simple while loop that checks whether the current character is NULL (or 0).
void charArrLength(char array[]) {
int arrLength = 0;
while (array[arrLength] != 0) {
arrLength++; //increment by 1
}
printf("Character array has %d elements", arrLength);
}
For this to work though, in the main() function, you need to declare your character array as a character pointer and then allocate the memory that you need based on the number of items that you ultimately wish to have inside your array.
void charArrLength(char array[]) {
int arrLength = 0;
while (array[arrLength] != 0) {
arrLength++;
}
printf("Character array has %d elements", arrLength); //should give 33
}
int main() {
char *array; //declare array as a pointer
int arraySize = 33; //can be anything
array = (char*) malloc(arraySize * sizeof(char));
charArrLength(array);
free(array); //free the previously allocated memory
}
Below you will see how I utilised this function in my assignment.
First, here is the above function tailored to my needs.
int isItemExists(char itemPrefixes[], char itemPrefix) {
int count = 0; //declare count variable and set to 0
int itemIndex = -1; //declare item index variable and set it to -1 as default
while (itemPrefixes[count] != 0) {
count++;
}
for (int i = 0; i < count; i++) {
if (itemPrefix == itemPrefixes[i]) {
itemIndex = i; //if item exists, set item index to i
}
}
return itemIndex;
}
Then, how I declared the itemPrefixes array in main() function and how I allocated the needed memory based on n (the number of items the user would like to add to itemPrefixes array).
char *itemPrefixes;
int n = 0; //number of items to be added variable
printf("> Enter how many items to add: ");
scanf("%d", &n);
//allocate n * size of char data type bytes of memory
itemPrefixes = (char*) malloc(n * sizeof(char));
And finally, here is how that function was used after all.
do {
printf("\n\n> Enter prefix for item %d: ", i + 1);
scanf(" %c", &itemPrefix);
//prompt the user if that itemPrefix already exists
if (isItemExists(itemPrefixes, itemPrefix) != -1) {
printf("\nItem prefix already exists! Try another one.\n");
}
} while (isItemExists(itemPrefixes, itemPrefix) != -1);
Also, in the end of the code I free the previously allocated memory.
free(itemPrefixes);
To clear this out, again, this could be much easier if the conditions were different. The assignment was strict about not passing n as an argument. Nevertheless, I hope I help someone else that might be looking for this in the future!
Just for the sake of it, if anybody sees this and has something simpler to suggest, feel free to tell me.
Related
int count(char letter, int* array, int number)
{
int sum= 0;
int i;
for(i = 0; i < number; ++i)
{
if(array[i] == letter)
++sum;
}
return sum;
}
int main(){
char array[] = { 'A','B','B','C'};
int number= sizeof(array) / sizeof(char);
count("A", array, number);
return 0;
}
I am attempting to count an occurrence of a particular character in an array and get nothing. The problem is certainly in the way I pass the character argument, but I struggle to find a similar example online.
I did a bit of tweaking of your code so that the parameters in your function align with the parameters passed when your function is called. Following is an example of what your code might look like in order to count characters.
#include <stdio.h>
#include <stdlib.h>
int count(char letter, char* array, int number) /* Made second parameter a character array in lieu of an integer array */
{
int sum= 0;
int i;
for(i = 0; i < number; ++i)
{
if(array[i] == letter)
++sum;
}
return sum;
}
int main()
{
char array[] = { 'A','B','B','C'};
int number= sizeof(array) / sizeof(char) ;
printf("Count: %d\n",count('A', array, number)); /* Changed from string constant "A" to character 'A' */
return 0;
}
First off, you appear to want to send a character as your first parameter to your function. In your original code you were actually sending a string constant as "A" was enclosed in double quotes and not single quotes. The second parameter is a character array (aka, a string). Therefore, in your function definition the second parameter there needs to be a character array and not an integer array. Characters take up one or two bytes of memory depending upon the system, and integers "usually" take up four bytes of memory. So there would be a mismatch in attempting to check out array values.
Using your revised function to produce output for a "printf" call, I received the following output on my terminal.
Count: 1
So probably the biggest takeaway from this is that characters (e.g. 'A') are different from string constants (e.g. "A"), and characters, even though they equate to an integer value, utilize a smaller chunk of memory than do integers.
Hope that helps.
Regards.
This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 3 years ago.
I initially wrote a perfectly working C code for converting a positive integer (say 12345) to a string (i.e. "12345") and print it. The logic is simple: extracting the digits of the integer one-by-one by taking modulo 10 and reducing the integer by a factor of 10 each time (this occurs in the itos() function). The final string needs to hold the extracted digits in reverse order so as to match the original integer (cf. reverse() function).
#include <stdio.h>
#include <string.h>
char *reverse (char *s);
char *itos (int n);
int
main ()
{
int n = 12345;
char *s = itos (n);
printf ("%s", s);
return 1;
}
char *
itos (int n)
{
int d = 0;
char s[100];
int i = 0;
do
{
d = n % 10;
s[i] = (d + '0');
n = n / 10;
i++;
} while (n != 0);
s[i] = '\0';
return reverse(s);
}
char *
reverse (char *s)
{
int i = 0;
int j = strlen (s) - 1;
char temp;
while (i < j)
{
temp = s[i];
s[i] = s[j];
s[j] = temp;
i++;
j--;
}
return s;
}
You may compile it here. This works perfectly fine, but something strange happens if I return s instead of reverse(s) from the char* itos() function. That is:
#include <stdio.h>
#include <string.h>
char *itos (int n);
int
main ()
{
int n = 12345;
char *s = itos (n);
printf ("%s", s);
return 1;
}
char *
itos (int n)
{
int d = 0;
char s[100];
int i = 0;
do
{
d = n % 10;
s[i] = (d + '0');
n = n / 10;
i++;
} while (n != 0);
s[i] = '\0';
return s;
}
I'd have expected it to simply print the string "54321" instead of "12345". However, in the output screen, I simply get a (null). There might be a logical error in the char* itos() function, as in I might have done some illegal pointer operation, but I can't really locate the source of error.
I did try debugging by inserting print statements in several parts of the code. What I noticed is if I print the string s within the itos() function just before the return statement then it works fine and prints the string "54321". However, the print statement in the main() function still outputs a (null), which probably implies that there is some mismanagement of memory when the itos() function returns a character pointer to the main() function. Could someone please clarify?
Inside function itos you declared the variable s which is an array of 100 chars. This array is allocated somewhere after the start of the function and deallocated just before the function returns to its caller.
So when you put a printf inside itos, the variable s will still be a valid storage and this is why it worked as you intended. However as soon as itos returns, the memory reserved to the variable s should be considered deallocated thus can not be expected to still contain the data it had when itos was executing, creating undefined behavior if you rely on that.
Probably once deallocated, the memory pointed by s had its values modified, causing your function to not being able to proper convert the string back to a number.
char s[100] is only valid within itos. When the function returns, the memory becomes invalid, and accessing it through the pointer you returned is undefined behavior. You could instead allocate the memory dynamically, like this:
char* s = malloc(100);
When you do it this way, you need to free it when you're done with it (such as after the printf in main), like this:
free(s);
So, would defining a global character array be the way to go?
This would also work. Generally, it has its advantages and disadvantages over dynamically allocating the memory. For instance, it would occupy the memory at all times even if your function isn't using it. But to make up for it, the function runs faster because it doesn't have to dynamically allocate/delete the memory every time the function runs. But on the other hand it increases the startup time because it will zero-initialize the array. And of course you couldn't run it multiple times in parallel with one global array. But for this small program, none of those matter much.
I just learned about pointer and tried the program on the textbook,
"Declare an array of char type with size 8, ask the user to input a
string and then assign to the array. Develop a user-defined
function to sort the array in a non-decreasing order. Print the array
before and after sorting in the main function. The function
prototype is given as
void arr_sort( char * cPtr)"
I don't know very clear what mistake I have made.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void print(char *a[]);
void arr_sort( char *a[]);
int main()
{
int i;
char *array[8];
printf("Please input a string with size 7:");
for(i=0;i<7;i++)
{
scanf("%s",array);
}
printf("the array before sorting is");
print(array);
arr_sort(array);
print(array);
return 0;
}
void arr_sort( char *a[])
{
int i,j;
char *temp;
for(i=0;i<7;i++)
{
for(j=0;j<7;j++)
{
if(strcmp(a[j],a[j+1])>0)
{
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
}
void print(char *a[])
{
int i;
for(i=0;i<7;i++)
{
printf("%s ",a[i]);
}
}
doing a quick 'google' for a bubble sort, in C, results in:
// where 'n' is the number of entries in the array
// where 'array' is declared as 'int array[n];
for ( int c = 0 ; c < ( n - 1 ); c++ )
{
for ( int d = 0 ; d < n - c - 1; d++ )
{
if ( array[d] > array[d+1] ) /* For decreasing order use < */
{
int temp = array[d];
array[d] = array[d+1];
array[d+1] = temp;
}
}
}
Notice the limits on the upper bound of the index variables.
in your program you will be using char rather than int for temp and for the declaration of array[]
notice there is no need for anything in the string.h header file.
notice the limiting of the scope of the local variables c, d, and temp
The comments on your posted question cover the problems in the posted code, so I will not repeat all of them here.
for(i=0;i<7;i++) {
scanf("%s",array);
}
If you want 8 strings of length 7, you can't scanf them into the array. Your array is an array of pointers as defined here:
char *array[8];
Which is very different from this:
char array[8];
The first is an array that stores 8 pointers to strings. The second is an array that stores 8 characters. If you wanted to store a single string, you would do this:
char array[8];
printf("Please input a string with size 7: ");
scanf("%s", array);
Which is probably what you're used to at this point.
So, an array of pointers is just like a list of little arrows that point to blocks of memory. Your array doesn't store any characters itself, which is why you can't scanf directly into it.
int main(void) {
char *arr[8];
char new_word[8];
for(int i = 0; i < 8; i++) {
printf("Enter a new word of length 7: ");
scanf("%s", new_word);
arr[i] = malloc(strlen(new_word) + 1);
strcpy(arr[i], new_word);
}
for(int i = 0; i < 8; i++) {
printf("%s\n", arr[i]);
}
return 0;
}
This program creates two arrays: a pointer array (arr) and a character array (new_word). In the loop, you ask for seven strings of length 7, which is scanf'd into the character array. New memory is set aside for that string with malloc. Then, the string is copied into the block of memory that your first array pointer points to. We increment our array index with the for loop so that now we're using the next pointer, and so on.
It's important to use strcpy and copy the string out of the character array every time, otherwise at the end, you will just have an array of pointers pointing to a single string, new_word.
I want to implement the following function to print the contents of several char strings which are referenced through a pointer array. How can I determine how many pointers there are without passing the total as an argument of the function?
If it was an array of type int then it would be possible to use the sizeof() function but given that each item of my array is a pointer to a char string and each string could be of different length I don't think I can use this approach.
void printCharArray(char *arr[]){
int length = sizeof(arr) / sizeof(char); /* this does not give correct
number of items in the pointer array */
for (int i=1;i<=length; i++) {
printf("Array item: [%s]",arr[i]);
}
}
There is no built-in way to do this as C does not track the number of elements in an array for you like this.
You have a couple of options:
Pass the number of items in the array.
Set the last item to NULL so the code knows when it's reached the end. (This is kind of how C strings are handled.)
Otherwise modify your data structures to track the number of items in the array.
You cannot pass arrays as function arguments in C. Array names decay to pointers to their first element when used as a function argument, and you must separately specify the number of available array elements.
(In the context of a function parameter type, T[] and T* and T[12] are identical, so your function paramter might as well be char ** arr.)
Like so:
void printCharArray(char ** arr, size_t len) { /* ... */ }
int main()
{
char * arr[10] = { "Hello", "World", /* ... */ };
printCharArray(arr, sizeof(arr)/sizeof(*arr));
}
(Alternatively you can supply a "first" and a "one-past-the-end" pointer, which might be a bit more natural.)
If you set the element after the last valid element to null then you can do:
void printCharArray(char *arr[]){
for (int i=0; arr[i] != NULL; i++) {
printf("Array item: [%s]",arr[i]);
}
}
void printCharArray(char *arr[]) {
int length = sizeof(arr) / sizeof(char*); /* this does not give correct
number of items in the pointer array */
for (int i=0;i<=length; i++) {
printf("Array item: [%s]",arr[i]);
}
}
int main()
{
char * arr[10] = { "Hello", "World", /* ... */ };
printCharArray(arr);
}
first I declared y as a global var. htmTags is a *char[]. then in main()
y = 0;
while( htmTags[y] ) {
y++;
}
I did not add null at the end of array. provides actual count of array elements
or this works too
for (y=0;htmTags[y];y++) ;
I'm starting to learn C by reading K&R and going through some of the exercises. After some struggling, I was finally able to complete exercise 1-19 with the code below:
/* reverse: reverse the character string s */
void reverse(char s[], int slen)
{
char tmp[slen];
int i, j;
i = 0;
j = slen - 2; /* skip '\0' and \n */
tmp[i] = s[j];
while (i <= slen) {
++i;
--j;
tmp[i] = s[j];
}
/* code from copy function p 29 */
i = 0;
while ((s[i] = tmp[i]) != '\0')
++i;
}
My question is regarding that last bit of code where the tmp char array is copied to s. Why doesn't a simple s = tmp; work instead? Why does one have to iterate through the array copying index by index?
Maybe I'm just old and grumpy, but the other answers I've seen seem to miss the point completely.
C does not do array assignments, period. You cannot assign one array to another array by a simple assignment, unlike some other languages (PL/1, for instance; Pascal and many of its descendants too - Ada, Modula, Oberon, etc.). Nor does C really have a string type. It only has arrays of characters, and you can't copy arrays of characters (any more than you can copy arrays of any other type) without using a loop or a function call. [String literals don't really count as a string type.]
The only time arrays are copied is when the array is embedded in a structure and you do a structure assignment.
In my copy of K&R 2nd Edition, exercise 1-19 asks for a function reverse(s); in my copy of K&R 1st Edition, it was exercise 1-17 instead of 1-19, but the same question was asked.
Since pointers have not been covered at this stage, the solution should use indexes instead of pointers. I believe that leads to:
#include <string.h>
void reverse(char s[])
{
int i = 0;
int j = strlen(s) - 1;
while (i < j)
{
char c = s[i];
s[i++] = s[j];
s[j--] = c;
}
}
#ifdef TEST
#include <stdio.h>
int main(void)
{
char buffer[256];
while (fgets(buffer, sizeof(buffer), stdin) != 0)
{
int len = strlen(buffer);
if (len == 0)
break;
buffer[len-1] = '\0'; /* Zap newline */
printf("In: <<%s>>\n", buffer);
reverse(buffer);
printf("Out: <<%s>>\n", buffer);
}
return(0);
}
#endif /* TEST */
Compile this with -DTEST to include the test program and without to have just the function reverse() defined.
With the function signature given in the question, you avoid calling strlen() twice per line of input. Note the use of fgets() — even in test programs, it is a bad idea to use gets(). The downside of fgets() compared to gets() is that fgets() does not remove the trailing newline where gets() does. The upsides of fgets() are that you don't get array overflows and you can tell whether the program found a newline or whether it ran out of space (or data) before encountering a newline.
Your tmp array was declared on stack and so when your method completes, the memory used to hold the values will be freed because of scoping.
s = tmp means that s should point to the same memory location as tmp. This means that when tmp is freed, s will still be pointing to a now possible invalid, freed memory location.
This type of error is referred to as a dangling pointer.
Edit: This isn't a dangling modifier as pointed out in the comments of this answer. The issue is that saying s = tmp only changes what the parameter points to, not what the actual array that was passed.
Also, you could perform your reverse with a single pass and without allocating a whole array in memory by just swapping the values in place one by one:
void reverse(char s[], int slen) {
int i = 0; // First char
int j = slen - 2; // Last char minus \n\0
char tmp = 0; // Temp for the value being swapped
// Iterate over the array from the start until the two indexes collide.
while(i < j) {
tmp = s[i]; // Save the eariler char
s[i] = s[j]; // Replace it with the later char
s[j] = tmp; // Place the earlier char in the later char's spot
i++; // Move forwards with the early char
j--; // Move backwards with the later char
}
}
Because both s and tmp are memory addressees. If you s = tmp, both pointers would point to the same array.
Suppose that we have
char s[] ="ab";
/*
* Only for explanatory purposes.
*
*/
void foo(char s[]){
char tmp [] = "cd";
s= tmp;
}
foo(s);
after s= tmp you would have
s[0] : 'c'
s[1] : 'd'
s[2] : '\0'
Even though both arrays have the same data, a change in tmp, will affect both of them, because both arrays are actually the same. They both contain data that´s in the same memory address. So by changing any position of the tmp array, or destroying the tmp array, s would be affected in the same way.
By looping over the array, what you are doing is moving a piece of data from one memory address to another.
In my copy of K & R, pointers are explained in chapter 4. A quick glance through the first pages may be of help.
To round out the discussion here are two other possible ways to reverse as string:
void reverse(char string1[], char string2[])
{
int i = 0, len = 0;
while(string2[len] != '\0') // get the length of the string
len++;
while(len > 0)
{
string1[i] = string2[len-1]; // copy the elements in reverse
i++;
len--;
}
string1[i] = '\0'; // terminate the copied string
}
Or recursively:
void reverse (const char *const sPtr)
{
//if end of string
if (sPtr[0] == '\0')
{
return;
}
else //not end of the string...
{
reverse(&sPtr[1]); //recursive step
putchar(sPtr[0]); //display character
}
}
because tmp is a pointer, and you need to get a copy, not a "link".
In case of s=tmp, the value of tmp which is the also the beginning address of the array, would get copied to s.
That way both s and tmp will point to the same address in memory, which I think is not the purpose.
cheers
Try experimenting and see what happens when you do things like this:
void modifyArrayValues(char x[], int len)
{
for (int i = 0; i < len; ++i)
x[i] = i;
}
void attemptModifyArray(char x[], int len)
{
char y[10];
for (int i = 0; i < len; ++i)
y[i] = i;
x = y;
}
int main()
{
int i = 0;
char x[10];
for (i = 0; i < 10; ++i)
x[i] = 0;
attemptModifyArray(x, 10);
for (i=0; i < 10; ++i)
printf("%d\n", x[i]); // x is still all 0's
modifyArrayValues(x, 10);
for (i=0; i < 10; ++i)
printf("%d\n", x[i]); // now x has 0-9 in it
}
What happens when you modify the array directly in attemptModifyArray, you are just overwriting a local copy of the address of the array x. When you return, the original address is still in main's copy of x.
When you modify the values in the array in modifyArrayValues, you are modifying the actual array itself which has its address stored in modifyArrayValues local copy of x. When you return, x is still holding on to the same array, but you have modified the values in that array.
There's an interesting sub-thread in this thread about arrays and pointers
I found this link on wikipedia with a peculiar code snippet showing just how 'plasticine' C can be!
/* x designates an array */
x[i] = 1;
*(x + i) = 1;
*(i + x) = 1;
i[x] = 1; /* strange, but correct: i[x] is equivalent to *(i + x) */
Of course what's even more confusing in C is that I can do this:
unsigned int someval = 0xDEADD00D;
char *p = (char *)&someval;
p[2] = (char)0xF0;
So the interchangibility of pointers and arrays seems so deep-set in the C language as to be almost intentional.
What does everyone else think?
---Original Post---
s and tmp are both pointers so doing s = tmp will simply make s point at the address where tmp lives in memory.
Another problem with what you outlined is that tmp is a local variable so will become 'undefined' when it goes out of scope i.e when the function returns.
Make sure you thoroughly grasp these three concepts and you won't go far wrong
Scope
The difference between the stack and the heap
Pointers
Hope that helps and keep going!
A very straight forward answer would be -
both s and tmp are pointers to a memory location and not the arrays themselves.
In other words, s and tmp are memory addresses where the array values are stored but not the values themselves.
And one of the common ways to access these array values are by using indices like s[0] or tmp[0].
Now, if you will try to simply copy, s = tmp, the memory address of tmp array will be copied over to s. This means that, the original s array will be lost and even s memory pointer will now point to tmp array.
You will understand these concepts well with due time so keep going through the book.
I hope this elementary explanation helps.