4

A way of ending a char array before it becomes full is to put '\0' at end, like-

single_str[5] ='\0';

Then how to end a 2D char array in that way?

6
  • 2
    2D char array == string vector == array of char[] pointers. Then last pointer should be NULL Commented Mar 14, 2015 at 7:20
  • @tutankhamun: This only works for "scattered" arrays. For a lineare array like char a[3][5] to what do you want to assign the NULL? Commented Mar 14, 2015 at 7:29
  • @tutankhamun probably.. but how does that work.. how the NULL got there? is it assigned by the compiler? Commented Mar 14, 2015 at 7:41
  • 1
    @tutankhamun a 2D array is not an array of pointers. Commented Mar 14, 2015 at 8:57
  • @user4647543 Probably I understood the question wrong. It would be nice if the question contents an example. Commented Mar 14, 2015 at 9:52

4 Answers 4

4

In practice, you should in C avoid thinking of 2D arrays. Stricto sensu, the C language don't know about 2D arrays, only about arrays of arrays (fixed length, all of the same size) or about arrays of pointers (or array of aggregates or scalars).

You might use an array of string pointers. C strings are conventionally ended by a zero byte. Here is an example of constant array (of constant strings, i.e. const char* pointers) ended by a NULL string

const char*const arrstr[] = {
   "Hello",
   "Nice",
   "World",
   NULL
};

On my machine, sizeof(const char*) is 8, so sizeof(arrstr) is 32; and sizeof("Nice") is 5.

You could print all the array members with

for (const char*const* p = arrstr; *p; p++) printf("%s\n", *p);

You could use in C99 a structure ending with a flexible array member, e.g.

struct my_string_array_st {
   unsigned len;
   char* arr[]; // array of len pointers */
};

then you might have a constructor function which build such string arrays with empty content like

struct my_string_array_st* make_string_array(unsigned ln) {
  struct my_string_array_st*p
     = malloc(sizeof(struct my_string_array_st) + len*sizeof(char*));
  if (!p) { perror("malloc"); exit(EXIT_FAILURE); };
  p->len = ln;
  for (unsigned ix=0; ix<ln; ix+) p->arr[ix] = NULL;
  return p; }

you'll then decide (this is your convention to follow) that each string inside is heap-allocated with strdup - so you don't have two aliased pointers inside. Here is the function to set a string (and release the previous one, if needed)

void 
set_string_array(struct my_string_array_st*p, unsigned ix, const char*str) {
  if (!p || ix>=p->len) return;
  free(p->arr[ix]);
  char* s = NULL;
  if (str) {
     s = strdup(str);
     if (!s) { perror("strdup"); exit(EXIT_FAILURE); };
  };
  p->arr[ix] = s;
}

(recall that you are allowed to free(3) a NULL pointer; it is a no-op) and here is a destructor function, releasing all the internal strings.

void destroy_string_array(struct my_string_array_st*p) {
  if (!p) return;
  unsigned l = p->len;
  for (unsigned ix=0; ix<l; ix++) free(p->arr[ix]);
  free (p);
}

Of course, here is an accessor function:

const char* nth_string_array(struct my_string_array_st*p, unsigned ix)
{
  if (!p || ix>=p->len) return NULL;
  return p->arr[ix];
}
Sign up to request clarification or add additional context in comments.

Comments

2

You can use an empty string "":

#include <stdio.h>

int main(void)
{
    char arr[][3] = {"ab", "cd", ""};
    char (*p)[3] = arr;

    while (**p) { /* while not an empty string */
        printf("%s\n", *p);
        p++;
    } 
    return 0;
}

If arr can contain an empty string, you can use a non printable character, like ETX (end of text):

#include <stdio.h>

int main(void)
{
    char arr[][3] = {"ab", "", "\x03"};
    char (*p)[3] = arr;

    while (**p != '\x03') {
        printf("%s\n", *p);
        p++;
    } 
    return 0;
}

For a a non modifiable array you can use NULL:

#include <stdio.h>

int main(void)
{
    char *arr[] = {"ab", "cd", NULL}; /* Read only */
    char **p = arr;

    while (*p) { /* while not NULL */
        printf("%s\n", *p);
        p++;
    } 
    return 0;
}

Comments

2

You need to define a sentinel value.

As sentinel for linear and scattered arrays this can be any valid C-"string", which is known to not be used as play-load value during operation for any of the array's elements.

For scattered arrays also NULL can be used as sentinel.

Example for linear array

Define the sentinel value:

#define END_OF_ARRAY "__EOA__" 

or just the empty "string":

#define END_OF_ARRAY "" 

Note that the sentinel has to be a C-"string" when used with a linear array!

char array [][8] = {
  "1st",
  "2nd",
  END_OF_ARRAY
}

To detect the array's size you then might use a function like this:

ssize_t get_array_size(const char (*parray)[][8])
{
  ssize_t s = -1;

  if (NULL == parray)
  {
    errno = EINVAL;
  }
  else
  {
    s = 0;

    while (strcmp((*parray)[s], END_OF_ARRAY))
    {
      ++s;
    }
  }

  return s;
}

Example for scattered array

Define the sentinel value:

#define END_OF_ARRAY NULL

or also possible

#define END_OF_ARRAY "__EOA__" 

Note that commonly NULL is used.

char * array[] = {
  "1st",
  "2nd",
  END_OF_ARRAY 
}

To detect the array's size you then might use a function like this:

ssize_t get_array_size(const char *** parray)
{
  ssize_t s = -1;

  if (NULL == parray || NULL == *parray)
  {
    errno = EINVAL;
  }
  else
  {
    s = 0;

    while ((*parray)[s] != END_OF_ARRAY)
    {
      ++s;
    }
  }

  return s;
}

Usage

For both examples call it like this:

int main(void)
{
  ssize_t result = get_array_size(&array);
  if (-1 == result)
  {
    perror("get_array_size() failed");
  }
  else
  {
    size_t size = result;
    printf("number of elements: %zu\n", size)
  }

  return 0;
}

Simpler approach for scattered arrays

Define the sentinel value:

#define END_OF_ARRAY NULL

or also possible

#define END_OF_ARRAY "__EOA__" 

Note that commonly NULL is used.

char * array[] = {
  "1st",
  "2nd",
  END_OF_ARRAY 
}

To detect the array's size you then might use a function like this:

ssize_t get_array_size(const char ** parray)
{
  ssize_t s = -1;

  if (NULL == parray)
  {
    errno = EINVAL;
  }
  else
  {
    s = 0;

    while (parray[s] != END_OF_ARRAY)
    {
      ++s;
    }
  }

  return s;
}

Usage

Note when calling this simpler implementation the array is passed directly and not its address is being passed:

int main(void)
{
  ssize_t result = get_array_size(array);
  if (-1 == result)
  {
    perror("get_array_size() failed");
  }
  else
  {
    size_t size = result;
    printf("number of elements: %zu\n", size)
  }

  return 0;
}

1 Comment

I'd suggest using the empty string as EOA unless it's known that empty strings are going to be permitted in the list
1

You can assign like this.

  char ar[3][20];
  ar[2][0]='\0';

You can place the null at which position you need. Consider you need to place the null in 1th line 10th column you can do like this.

  ar[1][10]='\0';

Like this where you need to place the null you can place the null.

1 Comment

shorter way: ar[1][10] = 0;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.