Initialize array of strings - c

What is the right way to initialize char** ?
I get coverity error - Uninitialized pointer read (UNINIT) when trying:
char **values = NULL;
or
char **values = { NULL };

This example program illustrates initialization of an array of C strings.
#include <stdio.h>
const char * array[] = {
"First entry",
"Second entry",
"Third entry",
};
#define n_array (sizeof (array) / sizeof (const char *))
int main ()
{
int i;
for (i = 0; i < n_array; i++) {
printf ("%d: %s\n", i, array[i]);
}
return 0;
}
It prints out the following:
0: First entry
1: Second entry
2: Third entry

Its fine to just do char **strings;, char **strings = NULL, or char **strings = {NULL}
but to initialize it you'd have to use malloc:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(){
// allocate space for 5 pointers to strings
char **strings = (char**)malloc(5*sizeof(char*));
int i = 0;
//allocate space for each string
// here allocate 50 bytes, which is more than enough for the strings
for(i = 0; i < 5; i++){
printf("%d\n", i);
strings[i] = (char*)malloc(50*sizeof(char));
}
//assign them all something
sprintf(strings[0], "bird goes tweet");
sprintf(strings[1], "mouse goes squeak");
sprintf(strings[2], "cow goes moo");
sprintf(strings[3], "frog goes croak");
sprintf(strings[4], "what does the fox say?");
// Print it out
for(i = 0; i < 5; i++){
printf("Line #%d(length: %lu): %s\n", i, strlen(strings[i]),strings[i]);
}
//Free each string
for(i = 0; i < 5; i++){
free(strings[i]);
}
//finally release the first string
free(strings);
return 0;
}

There is no right way, but you can initialize an array of literals:
char **values = (char *[]){"a", "b", "c"};
or you can allocate each and initialize it:
char **values = malloc(sizeof(char*) * s);
for(...)
{
values[i] = malloc(sizeof(char) * l);
//or
values[i] = "hello";
}

Related

Convert an array of string into an array array of strings

I have an array of strings: {"foo", "bar", "baz"} and I want to convert it into an array array of string: {{"foo", "bar", "baz"}}, (part of a bigger project).
My program will use args as an array of strings, so the input is: ./a.out foo bar baz.
With 1 and 3 arguments it works nice, but with 2 arguments it gives me segmentation fault.
My code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char ***args2cmd(int argc, char **args){
//Create array of array of strings
char ***arr = malloc(sizeof(char ***));
int tami = 0;
int tamj = 0;
//Arry of strings
arr[tami] = malloc(sizeof(char **));
//String
arr[tami][tamj] = malloc(sizeof(char *));
for(int i=0; i<argc; i++){
tamj++;
arr = realloc(arr, tamj * sizeof(**arr));
arr[tami][tamj-1] = args[i];
}
return arr;
}
int main(int argc, char **args) {
char ***arr = args2cmd(argc, args);
for(int i=0; arr[i]; i++){
for(int j=0; arr[i][j]; j++){
printf("%s ", arr[i][j]);
}
printf("\n");
}
return 0;
}
Bellow is a little code demonstration of how you could use an array of void pointers to accomplish your task. Code is fully commented with all relevant explanations. Compile with gcc -o astr astr.c.
Call with ./astr hello world from command line, for example.
/* astr.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
/* #n is the number of string you passed the function */
char **build_array(int n, ...)
{
/* no error checking...
* +1 because we terminate the array with a NULL
*/
char **s = malloc((n + 1) * sizeof(*s));
va_list ap;
int i;
va_start(ap, n);
for(i = 0; i < n; i++)
s[i] = va_arg(ap, char *);
va_end(ap);
/* terminate the array with a NULL */
s[i] = NULL;
return s;
}
int main(int argc, char **argv)
{
/* array of strings is just an array of pointers...
*
* Since you can play around with void points _by the standard_,
* we can just make an array of voids to hold whatever pointers we
* want, IFF we keep track of the types for the conversions.
*
* Say we do:
*
* astr[0] = argv; // this is type (char **)
*
* and them we do
*
* float **foo = astr[0]; // VALID SYNTAX, but WRONG SEMANTIC
*
* The above is valid syntax since we can convert to and from
* void pointers, but we stored (char**) in astr[0], not
* (float**), and this will blow up in your face.
*/
void **astr;
/* alloc space for the array of strings.
* no error cheking!
*/
astr = malloc(3 * sizeof(*astr));
/* the first element is the command line.
* You could make a function to copy #argv into a new array
*/
astr[0] = argv;
/* just a helper function to build some more arrays */
for(int i = 1; i < 3; i++)
astr[i] = build_array(3, "hello", "world", "!!!");
for(int i = 0; i < 3; i++) {
char **s = astr[i];
printf("Array #%d at addr %p\n", i, s);
/* This assumption is dangerous! You should always KNOW
* the size of your arrays
*/
for(int j = 0; s[j]; j++)
printf("s[%d] = %s\n", j, s[j]);
}
return 0;
}
After your comment:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char ***args2cmd(int argc, char **args)
{
//Create array of array of strings
// FIRST malloc()
char ***arr = malloc(sizeof(char ***));
int tami = 0;
int tamj = 0;
/* arr => 1 slot for 1 array
*/
//Arry of strings
// SECOND malloc
arr[tami] = malloc((argc + 1) * sizeof(char **));
/* arr[tami] = malloc(sizeof(char**)) gives us just
* arr[0] => 1 slot, which doesn't make sense.
*
* So we change it, because WE KNOW the size of the array! It's
* going to hold argc + 1 strings. Why the +1? Because you use the
* trick of stoping loops based on a NULL element.
*
*
* Keep in mind that #tami is bound the the amount of space pointed
* to by arr! So, that's the first malloc() you did.
*
*/
//String
//arr[tami][tamj] = malloc(sizeof(char *));
/* arr[0][0] = 1 slot
*
* If this is a string, why only one slot?
* You need more space for strings, ie:
* arr[tami][tamj] = malloc(strlen(something))
*
* So we comment this out, since it doesn't make any sense here.
*/
int i; /* so we can use it later for the NULL */
for (i = 0; i < argc; i++) {
/* strdup() will alloc space and copy the string you give it
* to this new region, then it will return your region. It's
* similar to doing:
* char *s1 = "hello":
* char *s2 = malloc(strlen(s1));
* return strcpy(s2, s1);
*/
arr[tami][i] = strdup(args[i]);
}
/* you assume the arrays end with NULL, so you
* have to put it here
*/
arr[tami][i] = NULL;
return arr;
}
int main(int argc, char **args)
{
char ***arr = args2cmd(argc, args);
for (int i = 0; arr[i]; i++) {
for (int j = 0; arr[i][j]; j++) {
printf("%s ", arr[i][j]);
}
printf("\n");
}
return 0;
}

Am I returning double char the correct way?

I am currently practicing malloc and trying to create an array of strings in c.
The following is my little program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int read_arguments(char*s[]);
char** copy_argv(char*s[]);
void free_char_ary(char*s[]);
int main(int argc, char* argv[])
{
int count = read_arguments(argv);
char **arr = copy_argv(argv);
for(int i = 0; i < count; i++)
{
printf("%s\n", arr[i]);
}
free_char_ary(arr);
exit(0);
}
int read_arguments(char*s[])
{
int count = 0;
while(*s)
{
count++;
s++;
}
return count;
}
char** copy_argv(char*s[])
{
int result = read_arguments(s);
printf("result = %d\n", result);
char** ary = (char**) malloc(result * sizeof(char*));
for(int i = 0; i < result; i++)
{
ary[i] = (char*) malloc(100 * sizeof(char));
strcpy(ary[i], s[i]);
}
return ary;
}
void free_char_ary(char*s[])
{
int count = read_arguments(s);
printf("count = %d\n", count);
for(int i = 0; i < count; i++)
{
free(s[i]);
}
free(s);
}
The result is weird. If i execute for like 4 arguments it is fine, but if i execute with 5 arguments then i get segmentation fault at the free_char_ary. I found that the int returned by read_arguments is different after i copy_argv to char**arr. Am I using the double char pointer the correct way? Why is the result different?
The function free_char_ary has undefined behavior because the dynamically allocated array does not contain an element with the value NULL. As a result the call of read_arguments within the function invokes the undefined behavior.
void free_char_ary(char*s[])
{
int count = read_arguments(s);
printf("count = %d\n", count);
for(int i = 0; i < count; i++)
{
free(s[i]);
}
free(s);
}
You should append the dynamically allocated array with a null pointer the same way as the array argv is defined. Or you could pass to the function the actual number of elements in the dynamically allocated array,

Is there any way whatsoever of 'converting' a char array to a char* array in C?

Im just curious if there is anyway of directly converting a char array to a char* array such as:
char charArray[5]={'h','e','l','l','o'};
'Converted' to:
char *pointerArray[5]={"h","e","l","l","o"};
How about this?
#include <stdio.h>
#include <stdlib.h>
char **convert_array(char *arr_in, size_t arr_in_sz)
{
char **arr_out = (char **)malloc(arr_in_sz * sizeof(char *));
for (size_t i = 0; i < arr_in_sz; ++i) {
arr_out[i] = (char *)malloc(2);
arr_out[i][0] = arr_in[i];
arr_out[i][1] = '\0';
}
return arr_out;
}
void free_array(char **arr, size_t arr_sz)
{
for (size_t i = 0; i < arr_sz; ++i)
free(arr[i]);
free(arr);
}
int main()
{
char array_char[] = {'h', 'i'};
char **array_str = convert_array(array_char, sizeof(array_char));
for (size_t i = 0; i < sizeof(array_char); ++i)
printf("%s\n", array_str[i]);
free_array(array_str, sizeof(array_char));
}
You only need a place to store the string literals. You need twice as much memory as for the charArray - to store letters and zero terminating characters, one zero for each letter - twice as much memory. Then initialize pointerarray to point to every second character inside memory. Like so:
#include <stdio.h>
int main() {
char chararray[5]={'h','e','l','l','o'};
char memory[sizeof(chararray) * 2];
for (unsigned i = 0; i < sizeof(chararray); ++i) {
memory[i * 2] = chararray[i];
memory[i * 2 + 1] = '\0';
}
char *pointerarray[5];
for (unsigned i = 0; i < sizeof(chararray); ++i) {
// this loop could me merged with above loop
pointerarray[i] = &memory[i * 2];
}
for (unsigned i = 0; i < 5; ++i) {
printf("%s\n", pointerarray[i]);
}
}
The first one is one dimensional array and secon one is two dimensional. So if you just use pointer like that :
char *pointerArray it means you have an array but you can not assign like in the first example.

need help in understanding passing char* [] to function

I am trying to pass a array of pointers to string to a function where I need to set the values. In the passing function I do not know the number of strings I will get, the called function is calling some other function which returns list of strings.
Sample code below:
int main() {
char** list;
create(list);
}
int create(char **array) {
char* str[] = { "hello", "dear" };
int len;
int i = 0;
for (i = 0; i < 2; i++) {
len = strlen(str[i]);
printf("%d\n", len);
*(array + i) = (char*) malloc(len * sizeof(char*));
strcpy(*(array + i), str[i]);
i++;
}
return 1;
}
This gives me segmentation fault.
What wrong am I doing here. Please help.
Thanks
EDIT
Updated code from below comments:
int main() {
char** list;
create(list);
int i = 0;
for (i = 0; i < 2; i++) {
printf("%s\n", list[i]); // segmentation fault
}
}
int create(char **array) {
char* str[] = { "hello", "dear" };
int len;
int i = 0;
array = malloc(2 * sizeof(char*));
for (i = 0; i < 2; i++) {
len = strlen(str[i]);
printf("%d\n", len);
*(array + i) = (char*) malloc(len * sizeof(char));
strcpy(*(array + i), str[i]);
printf("%s\n", array[i]); // this prints
}
return 1;
}
Now getting segmentation fault in main while printing the list.
Actual code where I am reading the strings
int i;
for ( i=0; i<reply->elements; i++ )
{
printf( "Result: %d---%s\n", i,reply->element[i]->str );
*array[i] = (char*)malloc(strlen(reply->element[i]->str));
printf("***");
strcpy(array[i],reply->element[i]->str);
printf( "Array[%d]: %s\n", i,array[i] );
}
You correctly alloc memory for the individual strings, but fail to alloc some for the array itself.
You should use:
int main() {
char* list[8] = {0}; /* initialize pointers to NULL */
create(list);
/* free allocated memory - free(NULL) is legal and is a noop */
for (i=0; i<sizeof(list)/sizeof(list[0]); i++) free(list[i]);
return 0; /* never return random value from main */
}
And you should remove the i++ at the end of the loop in function create because it leads to a double increment.
Alternatively you could alloc the array itself in the function create:
int create(char ***array) {
char* str[] = { "hello", "dear" };
int len;
int i = 0;
*array = malloc(1 + sizeof(str)/sizeof(str[0]));
for (i = 0; i < 2; i++) {
len = strlen(str[i]) + 1;
printf("%d\n", len);
(*array)[i] = malloc(len * sizeof(char*));
strcpy((*array)[i], str[i]);
}
(*array)[i] = NULL;
return i;
}
int main() {
char** list;
create(&list);
}
In above code, the length of the array is the return value from create, and the last element of list is a NULL (in the same logic as argc/argv).
You need to allocate some space for list or undefined behavior occurs:
char* list[2];
You increment i twice; therefore, remove the i++ from the bottom of the for loop.
Minor notes:
refer to string literals as const char*
use array[i] instead of *(array + i)
don't cast the result of malloc
malloc allocates too much space as you allocate len char*s, even though you need just chars. Also, as #CoolGuy noted, you need one extra byte for the null byte. Replace the allocation with
array[i] = malloc(len * sizeof(char) + sizeof(char));
or
array[i] = malloc(len + 1);
call free after malloc
you assign 0 twice to i; remove the initialization
You allocate two arrays (char*) to store the strings "hello" and "dear" but does not allocate the array (char**) containing those two string array.
I would suggest you to change declaration of function create to this -
int create(char ***array);
And call it like this -
create(&list);
In function create allocate memory like this -
*array = malloc(2 * sizeof(char*));
for (i = 0; i < 2; i++)
{
len = strlen(str[i]);
printf("%d\n", len);
(*array)[i] =malloc(len * sizeof(char*)+1);
strcpy((*array)[i], str[i]);
}
And do the printing as you do in main.
Note - free memory that you allocate.
And you should declare len as type size_t -> size_t len;
and print it with %zu specifier in printf .
See working code here -https://ideone.com/GX2k9T

C - strcat in for loop

I m writing a little C program and want to know why my output in the console is "0", "0" [...]? The output i expect is "ab", "ac", [...].
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int i;
int j;
char string[] = "abc";
char output[8];
int length = size(&string[0]);
for(i=0; i<length; i++) {
for(j=0; j<length; j++){
char a = string[i];
strcat(output, &a);
char b = string[j];
strcat(output, &b);
printf("%c\n", output);
}
}
return 0;
}
Mistake #1. You have not initialised output[] so strcat() will not validly find a nul terminator to append to.
output[0] = 0;
Mistake #2. strcat() isn't the right way of appending chars anyway.
Mistake #3. Your loop controls aren't right. See below.
Mistake #4. Your length is the size of a char* pointer.
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
int i, j;
char string[] = "abc";
char output[8];
int length = strlen (string); // corrected
for(i=0; i<length-1; i++) { // amended loop
for(j=i+1; j<length; j++) { // amended loop
output[0] = string [i];
output[1] = string [j];
output[2] = 0; // string terminator
printf("%s\n", output); // uses string type not char
}
}
return 0;
}
Program output:
ab
ac
bc
If I have understood correctly what you are trying to do then the program will look the following way
#include <stdio.h>
int main(int argc, char *argv[])
{
char string[] = "abc";
char output[3];
size_t length = sizeof( string ) - 1;
for ( size_t i = 0; i < length; i++ )
{
for ( size_t j = 0; j < length; j++ )
{
if ( i != j )
{
output[0] = string[i];
output[1] = string[j];
output[2] = '\0';
puts( output );
}
}
}
return 0;
}
The output is
ab
ac
ba
bc
ca
cb
If your compiler does not allow to declare variables within the control statement of the loop then you can declare i and j in the beginning of the program.
size_t i, j;
If you want to include combinations like "aa" then you simply may remove the if statement withing the inner loop.
char a = string[i];
strcat(output, &a);
leads to undefined behavior since strcat expects a null terminated string in the second argument. Same thing applies to:
char b = string[j];
strcat(output, &b);
Perhaps you meant to use:
output[0] = a;
output[1] = b;
output[2] = '\0';
Here's the updated for loop:
for(i=0; i<length; i++) {
for(j=0; j<length; j++){
output[0] = a;
output[1] = b;
output[2] = '\0';
printf("%s\n", output);
// ^^ use %s to print a string, not %c.
}
}
If you want to use strcat you must know that it expects a string not a character and there is an important difference, when you pass &a strcat thinks it is the address of a pointer to a string, and you should get most likely a segmentation fault, here I show your own code, modified to use strcat but you don't really need it for this task.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int i;
int j;
char string[] = "abc";
int length = strlen(&string[0]);
for(i = 0 ; i < length ; i++)
{
for(j= i + 1 ; j < length ; j++)
{
/* initialize output to 0 more importantly to have a terminating null byte */
char output[3] = {0};
/*
* create a string and initialize it with 2 char's
* - the first one, the one you want to append to output
* - the second one is required by strcat, to mark the end of the string
*/
char a[2] = {string[i], 0};
strcat(output, a);
/* same as above */
char b[2] = {string[j], 0};
strcat(output, b);
printf("%s\n", output);
}
}
return 0;
}
you could do this without strcat unless you are trying to learn how to use strcat, this is an example of how to do it without strcat.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int i;
int j;
char string[] = "abc";
int length = strlen(&string[0]);
for(i = 0 ; i < length ; i++)
{
for(j= i + 1 ; j < length ; j++)
{
char output[3] = {string[i], string[j], 0};
printf("%s\n", output);
}
}
return 0;
}

Resources