Similar to this question: 2d array, using calloc in C
I need help initializing a 2D char array that will all be initialized to some value (in this case '0'). I have tried many different methods and I am pulling my hair out. Please let me know what I am doing wrong. This code doesn't work. Thanks!
char** init_array() {
char newarray[5][10];
int i, j;
for (i = 0; i < 5; i++) {
for (j = 0; j < 10; j++) {
newarray[i][j] = '0';
}
}
return newarray;
}
char **array = init_array();
The errors I get from gcc when I try to compile:
test.c: In function ‘init_array’:
test.c:12:2: warning: return from incompatible pointer type [enabled by default]
return newarray;
^
test.c:12:2: warning: function returns address of local variable [-Wreturn-local-addr]
test.c: At top level:
test.c:14:1: error: initializer element is not constant
char **array = init_array();
Should it be like this?
char newarray[5][10];
char** init_array() {
int i, j;
for (i = 0; i < 5; i++) {
for (j = 0; j < 10; j++) {
newarray[i][j] = '0';
}
}
return newarray;
}
char **array = init_array();
I think pictures help. Here is char newarray[5][10]. It is a single memory block consisting of an array of 10 characters, and an array of five of those.
You could just clear it with a single memset call.
Here is char **array. It says array is a pointer.
What is it a pointer to?
a pointer to a character.
Keep in mind pointer arithmetic.
If array is a pointer that happens to point to a pointer,
then (*array) equals array[0], and that is the pointer that array points to.
What is array[1]?
It is the second pointer in the array that array points to.
What is array[0][0]?
It is the first character pointed at by the first pointer that array points to.
What is array[i][j]?
It is the jth character of the ith pointer that array points to.
So how are newarray and array related?
Simple.
newarray[i][j] is the jth character of the ith subarray of newarray.
So in that sense, it's just like array, but without all the pointers underneath.
What's the difference?
Well, the disadvantage of array is you have to build it up, piece by piece.
OTOH, the advantage is you can make it as big as you want when you build it up.
It doesn't have to live within a fixed size known in advance.
Clear as mud?
Per our discussion in the comments, here is a quick example of zeroing array values at the time of declaration. Note, the values are #defined as constants:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXSTR 10
#define MAXLEN 1024
int main () {
char myarray[MAXSTR][MAXLEN] = {{0}}; /* declare a static array of MAXSTR x MAXLEN */
/* copy various strings to statically declared storage */
strncpy (myarray[0]," This is the first string", strlen(" This is the first string")+1);
strncpy (myarray[1]," This is the second string", strlen(" This is the second string")+1);
strncpy (myarray[2]," This is the third string", strlen(" This is the third string")+1);
strncpy (myarray[3]," This is the fourth string", strlen(" This is the fourth string")+1);
strncpy (myarray[4]," This is the fifth string", strlen(" This is the fifth string")+1);
int i = 0;
/* print the values */
while (*myarray[i])
printf (" %s\n", myarray[i++]);
return 0;
}
output:
$ ./myar
This is the first string
This is the second string
This is the third string
This is the fourth string
This is the fifth string
build:
gcc -Wall -Wextra -o myar myarray.c
To avoid using a global (like the second sample code pasted above) and to avoid using malloc, you can define the array outside your function and pass it in, like this. You don't need to return anything because the array data itself is being modified. Notice that it's necessary to define the array's secondary dimension in the function signature:
void init_array(char ary[][10]) {
int i, j;
for (i = 0; i < 5; i++) {
for (j = 0; j < 10; j++) {
ary[i][j] = '0';
}
}
}
int main(void)
{
char newarray[5][10];
init_array(newarray);
printf("%c", newarray[1][1]); /* Testing the output */
return 0;
}
That returns '0'.
http://codepad.org/JbykYcyF
Related
is there a simple one liner I can use in C to allocate arrays in (pointer of arrays)
This line creates 10 pointers of arrays
char *out[10];
I can't do this
char *out[100]=(char[10][100])malloc(sizeof(char)*10*100);
error: cast specifies array type
same error with
char *out[10]=(char*[10])malloc(sizeof(char)*10*100);
do I need to do it in loop like this
int main()
{
char *out[10];
int x=0;
while(x<10)
{
*(out+x)=malloc(sizeof(char)*100);// is this line correct?
x++;
}
*out[0]='x';
printf("%c\n",out[0][0]);
free(out);
return 0;
}
but this cause warning that
req.c:75:3: warning: attempt to free a non-heap object ‘out’ [-Wfree-nonheap-object]
75 | free(out);
so do I need to allocate and free each array in (array of pointers) in loop
Can't I do allocation and free arrays in array of pointer in one line instead of loop?
or is there anything thing in my loop wrong too
To allocate an array of pointers to strings, you need to do:
char** out = malloc(sizeof(char*[10]));
The whole point of using this form is that each pointer in that array of pointers can be allocated with individual size, as is common with strings. So it doesn't make sense to allocate such with a "one-liner", or you are using the wrong type for the task.
In case you don't need individual sizes but are rather looking for a char [10][100] 2D array with static size, then the correct way to allocate such is:
char (*out)[100] = malloc(sizeof(char[10][100]));
You can allocate the full array in one single step and have pointers inside that array:
char *out[10];
data = malloc(100); //sizeof(char) is 1 by definition
for (int x=0; x<10; x++) {
out[i] = data + x * 10;
}
*out[0] = 'x';
printf("%c\n",out[0][0]);
free(data); // you must free what has been allocated
int i;
char** out = (char**)malloc(sizeof(char*)*10);
for(i = 0; i<10;i++)
out[i] = (char*)malloc(sizeof(char)*100);
out[1][1] = 'a';
OR with same dimensions
#include <stdio.h>
#include <stdlib.h>
void main()
{
int r = 10, c = 100; //Taking number of Rows and Columns
char *ptr, count = 0, i;
ptr = (char*)malloc((r * c) * sizeof(char)); //Dynamically Allocating Memory
for (i = 0; i < r * c; i++)
{
ptr[i] = i + 1; //Giving value to the pointer and simultaneously printing it.
printf("%c ", ptr[i]);
if ((i + 1) % c == 0)
{
printf("\n");
}
}
free(ptr);
}
I am playing with some code in C and also I am trying to understand relationship between pointers and arrays. As you probably know, when I want to make array it could be done like this:
char * arr = "abc";
or
char arr[] = {'a','b', 'c'};
But when I want to do 2D array. It must be done like this
char arr[3][10];
Why declaration like this crashes when I try to load string to that.
char * names[3];
for ( int i = 0; i < 3; i++ ) {
printf("Enter name %d: ", i+1 );
scanf("%s", names[i]);
}
// print names
printf("\nEntered names are: \n");
for ( int i = 0; i < 3; i++ ) {
printf("%s\n", names[i] );
}
It should be 2D array right? Because array is basically pointer.
Could you please explain that?
Thanks.
char * names[3];
Is not a 2D array, it's an array of three pointers to char, if you want to store char arrays in it you must allocate memory to each individual pointer, something like:
for(size_t i = 0; i < 3; i++){
names[i] = malloc(/*length your array of chars*/);
}
You can then store char arrays, using you example:
for(size_t i = 0; i < 3; i++){
printf("Enter name %ld: ", i + 1 );
scanf("%29s", names[i]); //for a malloc size of 30
}
Note that you must be careful with scanf, if the inputed string is longer then the memory allocated to store it you will have stack smashing, i.e. for names[i] with size of 30, you should use %29s specifier, instead of %s. Though this approach is not whitout its issues, namely possible characters left in stdin buffer, it's definitely safer.
Alternatively you can assign them string literals (in this case it's best to declare the array as const, otherwise if you try to edit one or more characters it'll result in a segfault):
const char* names[3];
for(size_t i = 0; i < 3; i++){
names[i] = "My string literal";
}
You can also make them point to existing char arrays:
char arr[3][10];
char* names[3];
for(size_t i = 0; i < 3; i++){
names[i] = arr[i];
}
char * names_1[3];
It's not a pointer. It's an array of pointers.
char names_2[3][10]={"one", "two", "three"};
char (*p_names_2)[10]=names_2;
Now it's a pointer to your 2D-Array. Just define a function and try to use it with your "pointers" as parameters.
void print_names(char names[][10], const int row){
for(int i=0; i<row; i++)
puts(names[i]);
}
Now call it with:
print_names(names_2, 3);
print_names(p_names_2, 3);
print_names(names_1, 3); //WRONG
And you'll see the difference.
char* names[3] is not strictly a 2D array (they don't exist in C or C++); it's an array of arrays. So each element of names contains simply a char*, which has not been initialised.
Note also that a c-style string is a null-terminated array of chars, so your original arr is not a c-style string. To make it a c-style string you would need:
char arr[] = {'a','b','c',0};
making it an array of length 4, not 3.
Missing off the null-terminator will mean that most functions will run off the end of the allocated memory, because they won't know when the string stops.
pointer is a type of variable, which can only contain an address of another variable. It can't contain any data. You can't store data into a pointer.Pointers should point at memory location.
So to use a pointer in the right way ,it must always point at a valid memory location in stack or memory dynamically allocated in heap.
this char * names[3] is an array of pointers ,so you need to reserve memory for it and then initialize it.You need to use some thing like this:
char *name[3];
for(int i=0;i<3;i++)
{
name[i]=malloc(strlen(string)+1);
}
also you should allocate memory for char *arr too.
char *arr=malloc(strlen(data)+1)
then initialized it.
I am trying to debug this code and I can't seem to find the error that is giving me this on the command line:
./thisa
thisa
isa
a
test
Instead, it needs to give me this:
./arguments
this
is
a
test
Assuming I enter "./arguments this is a test" as my input.
Any suggestions on where the bug might be?
Thanks!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void printArguments( int rows, int cols, char args[][ cols ] )
{
for (int i = 0; i < rows; i++) {
printf("%s\n", args[i]);
}
}
int main( int argc, char *argv[] )
{
// Figure out the length of the longest command-line argument.
int longest = 0;
for (int i = 0; i < argc; i++) {
int len = sizeof(argv[i])/sizeof(argv[0]);
if (len > longest) {
longest = len;
}
}
char (*words)[ longest + 1 ];
int n = argc;
words = (char (*)[longest + 1])malloc(n * (longest + 1) * sizeof(char));
// Copy each command-line argument to a row of this new array.
for (int i = 0; i < n; i++) {
strcpy(words[i], argv[i]);
}
// Call a function that's expecting the command-line arguments as a 2D array
printArguments( argc, longest + 1, words );
return 0;
}
There's quite a lot going on here. If you're simply trying to print the command-line arguments, you already have your answer in the guts of your helper function. Just use that code directly on argc/argv:
for (int i = 0; i < argc; i++) {
printf("%s\n", argv[i]);
}
Since you go to all the trouble of copying everything out into an array with a completely different format, I'm assuming that there's more to this question than what you've given us so I'll address the question/code as written.
As several others have mentioned, the line len = sizeof(argv[i])/sizeof(argv[0]) will always return 1 since argv[x] is a pointer. To measure the length of argument number x, all you need is sizeof(argv[x]).
The line char (*words)[ longest + 1 ] declares a pointer to an array of (longest+1) characters. You then allocate a much larger buffer ((longest+1) * argc bytes) and assign it to the pointer. It's not clear what you're trying to do here. Generally speaking, when allocating a character buffer, you'd do something like this:
char* my_ptr;
my_ptr = malloc(num_bytes);
You don't need to encode anything about the size of a 1-D buffer in the pointer, a normal character pointer is all you need. You also don't need to typecast the return value of malloc(). It returns a void*, which will implicitly convert to any other pointer type without a cast.
The next piece of code is likely where you're encountering a lot of your problems.
for (int i = 0; i < n; i++) {
strcpy(words[i], argv[i]);
}
Here, words is a pointer to a 1-dimensional array. This code starts by copying argument #0 to byte 0 of the destination (OK). The next time through the loop, it copies argument #1 to byte 1 of the destination. This is going to overwrite part of your first argument. You have room in this buffer to write all of the arguments without overlapping, but your pointer is only a 1-D pointer (you're treating it like a 2-D pointer). To treat the destination like a 2-D matrix, you'll need to do some of the pointer arithmetic yourself:
strcpy(words[i * (longest + 1)], argv[i]);
That will write the first argument at byte 0, the second at byte (longest+1), the third at byte 2*(longest+1), etc., ensuring that they won't overlap. You'll need to make a similar change to your helper function as well.
I don't understand what is wrong with the code below. It should malloc a 2D char array[5][30] (referred as LENGTH), pass it to a function and fill it with a string. It works just fine in the function; I can print it from there without any problem. But i cannot print even the first one from within the main() function (the application crashes if I try).
Could somebody please explain what I am doing wrong?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define LENGTH 5
void fillArray(char array[][LENGTH]) {
for (int i = 0; i < 5; i++) {
strcpy(array[i],"Hi World");
}
for (int i = 0; i < 5; i++) {
printf("%s\n",array[i]);
}
}
int main() {
char** array = (char**)malloc(5*sizeof(char*));
for (int i = 0; i < 5; i++) {
array[i] = (char*)malloc(LENGTH);
}
fillArray(array);
printf("%s",array[0]);
getchar();
return 0;
}
From main() function you are passing double pointer array and catching with 2D array array[][LENGTH] which is not correct, just saying double pointer is not similar to 2D array & vice versa.
for your task in fillArray() use array of char pointer as a argument, how many ? LENGTH.
void fillArray(char *array[LENGTH]) { /* this is okay */
for (int i = 0; i < 5; i++) {
strcpy(array[i],"Hi World");/*now in `array[i]` you can store any no of char. */
}
for (int i = 0; i < 5; i++) {
printf("%s\n",array[i]);
}
}
Also casting malloc() is not required And once job is done at last don't forget to free the dynamically allocated memory by calling free() for each.
The basic problem is that your function expects a 2 dimensional array but that is not what you pass to the function.
In main you allocate a 1 dimensional array of pointers. Then for each of these pointers, you allocate a 1 dimensional array of chars. That is not a 2D array.
So your function doesn't get what it expects and therefore your program fails.
So instead of:
char** array = (char**)malloc(5*sizeof(char*));
for (int i = 0; i < 5; i++) {
array[i] = (char*)malloc(LENGTH);
}
try this:
char (*array)[LENGTH] = malloc(5*LENGTH*sizeof(char*));
to get a correctly malloc'ed 2D array.
BTW:
I think you have a bug here
#define LENGTH 5
^
I guess you want 30 instead of 5
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.