What is the meaning of str[][20] - c

I just have a function here in C language, Can you please tell me what does str[ ][20] meaning and why do we need it
void printlist(char str[][20], int n) {
int i;
printf("\t*******************************\n");
printf("\tNo.\t\t\tName");
printf("\n\t*****************************\n");
for (i = 0; i < n; i++) {
printf("\t%d \t\t\t%s\n", i + 1, str[i]);
}
}
Thanks in advance

char str[][20], means that you have an unknown number of char arrays of size 20.
The parameter n to the function printlist specifies, how many rows there are in the specified array str.
Example:
int main()
{
char str[][20] = { "Hello", "World" };
printlist(str, sizeof str / 20); // <-- printlist(str, 2);
return 0;
}

Related

How to initialise new string in loop in C without malloc

I'm trying to instantiate a new string every iteration of a loop. What I tried was this:
int main(void) {
char *strs[10];
for (int i = 0; i < 10; i++) {
char str[10] = "";
char c = '0' + i;
strncat(str, &c, 1);
strs[i] = str;
}
for (int i = 0; i < 10; i++) {
printf("%s\n", strs[i]);
}
}
However, this prints all 9's, since C has conveniently decided that each iteration it would use the same address. I know that the following works, but just wanted to ask if it is possible to avoid malloc.
int main(void) {
char *strs[10];
for (int i = 0; i < 10; i++) {
char *str = malloc(sizeof(char) * 10);
char c = '0' + i;
strncat(str, &c, 1);
strs[i] = str;
}
for (int i = 0; i < 10; i++) {
printf("%s\n", strs[i]);
}
}
I am also interested in instantiating structs the same way without malloc. Is this possible?
A straightforward approach is to declare a two dimensional array like for example
char strs[10][2] = { "" };
for (int i = 0; i < 10; i++) {
strs[i][0] = '0' + i;
}
Here is a demonstration program
#include <stdio.h>
int main( void )
{
enum { N = 10 };
char strs[N][2] = { "" };
for ( int i = 0; i < N; i++ )
{
strs[i][0] = '0' + i;
}
for ( int i = 0; i < N; i++ )
{
printf( "%s ", strs[i] );
}
putchar( '\n' );
}
The program output is
0 1 2 3 4 5 6 7 8 9
Pay attention to that your second program has undefined behavior
char *str = malloc(sizeof(char) * 10);
char c = '0' + i;
strncat(str, &c, 1);
strs[i] = str;
The dynamically allocated array is not initialized. So the call of strncat invokes undefined behavior.
And in the both your programs this call strncat(str, &c, 1); does not build a string. So this call printf("%s\n", strs[i]);again invokes undefined behavior.
Regardless of data type, an object declared at block scope without storage class specifier static* has automatic storage duration. Its lifetime ends when execution of the innermost block containing its declaration terminates. Attempting to access such an object outside its lifetime produces undefined behavior.
If you want an object whose lifetime starts after the beginning of program execution and extends beyond the termination of the innermost block containing the start point, then dynamic allocation is your only choice.
* with static, the object has static storage duration -- the whole run of the program. You can access these via pointer from outside the scope of their identifiers, but for each such declaration there is only object serving the whole execution of the program.
"just wanted to ask if it is possible to avoid malloc."
Yes. The following makes use of Variable Length Arrays, and a function to do this without using calloc or malloc.
Running from the command prompt for example, enter:
your_program_name 10 5<return> to create an array of 10 elements each having room for 4 char plus a terminating null.
void populate_strs(int num, int longest, char sArr[num][longest])
{
for(int i=0;i<num; i++)
{
char c[2] = {0};
c[0] = '0' + (char)i;
c[1] = 0;//null terminate string
strncat(sArr[i], c, 1);//do not need & for string
}
}
int main(int argc, char *argv[])
{
if(argc != 3) printf("Usage error...");
int num_str = atoi(argv[1]);
int max_len = atoi(argv[2]);
char strs[num_str][max_len];
memset(strs, 0, sizeof strs);
populate_strs(num_str, max_len, strs);
for (int i = 0; i < 10; i++) {
printf("%s\n", strs[i]);
}
return 0;
}
And the same is true for an array of struct;
Given this for example:
typdef struct {
int val;
char str;
bool state;
} data_s;
...
int size = 0;
printf("Enter how many array elements of data_s to create.\n");
fscanf(stdin, "%d", &size);
data_s data[size];
memset(data, 0, sizeof data);
//use array of data;

String concatenation without libraries in C

I am having trouble concatenating strings in C without library function.
I tried the following:
#include <stdio.h>
struct word {
char *str;
int wordSize;
};
void concat(struct word words[], int arraySize, int maxSize) { // word array, its size, and max size given
char result[maxSize];
int resultSize = 0;
struct word tmp;
for (int i = 0; i < arraySize; i++) {
tmp = words[i];
for (int j = 0; j < words[i].wordSize; j++, resultSize++) {
result[resultSize + j] = tmp.str[j];
}
}
puts(result);
}
For example, if the struct array words contain [{"he", 2}, {"ll", 2}, {"o", 1}], the result should be hello. However, this code prints h�l�o where the second and fourth letters are questionmark. Can anyone help me debug this?
Keep it simple and the bugs will fix themselves. Don't mix up the position in the result buffer with the loop iterators. No need for temporary variables.
#include <stdio.h>
typedef struct {
char *str;
int wordSize;
} word;
void concat(word words[], int arraySize, int maxSize) {
char result[maxSize];
int count=0;
for(int i=0; i<arraySize; i++)
{
for(int j=0; j<words[i].wordSize; j++)
{
result[count]= words[i].str[j];
count++;
}
}
result[count] = '\0';
puts(result);
}
int main()
{
word w[3] = { {"he", 2}, {"ll", 2}, {"o", 1} };
concat(w, 3, 128);
}
In this for loop
for (int j = 0; j < words[i].wordSize; j++, resultSize++) {
result[resultSize + j] = tmp.str[j];
}
you are incrementing resultSize and j simultaneously while you need to increase only the variable j and after the loop increase the variable resultSize by j.
But in any case the function is wrong because there is no check that resultSize is less than maxSize.
And moreover the built string is not appended with the terminating zero '\0'. As a result this statement
puts(result);
invokes undefined behavior.
There is no need to create the variable length array
char result[maxSize];
just to output the concatenated string.
The function can be declared and defined the following way as it is shown in the demonstrative program below.
#include <stdio.h>
struct word {
char *str;
int wordSize;
};
void concat( const struct word words[], size_t arraySize, size_t maxSize )
{
for ( size_t i = 0, j = 0; i < maxSize && j < arraySize; j++ )
{
for ( size_t k = 0; i < maxSize && k < words[j].wordSize; i++, k++ )
{
putchar( words[j].str[k] );
}
}
putchar( '\n' );
}
int main(void)
{
struct word words[] =
{
{ "he", 2 }, { "ll", 2 }, { "o", 1 }
};
const size_t arraySize = sizeof( words ) / sizeof( *words );
concat( words, arraySize, 5 );
return 0;
}
The program output is
hello
You have a couple of problems here. result[resultSize + j] means you are effectively skipping over half the characters in result. Secondly, if you copy the entire string, including the null character, puts will stop printing the result string at the end of the first word itself. So you need to skip copying the string terminator and put it in at the end of your whole concatenated string.
#include <stdio.h>
struct word {
char *str;
int wordSize;
};
void concat(struct word words[], int maxSize) { // word array and max size given
char result[maxSize];
int resultSize = 0;
struct word tmp;
for (int i = 0; i < 3; i++) {
tmp = words[i];
// Keep copying the words to result, one after the other
// But drop the last NULL character
for (int j = 0; j < (words[i].wordSize - 1); j++, resultSize++) {
result[resultSize] = tmp.str[j];
}
}
// Put the NULL character in after all words have been copied
result[resultSize] = 0;
puts(result);
}
struct word mywords[] =
{
{ "TestWord", sizeof("TestWord")},
{ "TestWord2", sizeof("TestWord2")}
};
int main(void)
{
concat(mywords, 100);
return 0;
}

Count characters in an array of character strings?

Given an array of character strings such as...
char *example[] = {"s", "ss", "sss"};
How can I write a function to count the total number of chars in the array including the terminating characters, without using the standard library for strlen() etc.
Follows is my attempt
int countChars(char *array[], int len)
{
int total = 0, count = 0;
for (int i = 0; i < len; i++)
{
if (array[i] != NULL)
{
while (*array[i] != '\0') {
count++;
}
count++;
}
total += count;
}
return total;
}
An explanation on how char *array[] actually works for access wold be appreciated. I believe that it is supposed to be an array of pointers to strings.
You have to increment the index to consider each of the character.
Something like this:-
for (int i = 0; i < len; i++)
{
if (array[i] != NULL)
{
int j=0,count=0;
while (array[i][j++] != '\0') {
count++;
}
total += count;
}
}
Also reset the count or add to total at the end of all the calculation.
As an answer to your second question:-
char* array[] is basically denoting an array pointers each pointing
to the string literals with which you initialized it.
So once you use array[i] you should now think that it is nothing
other than a pointer to a string literal.
You need to reinitialize the variable count inside the for loop for each processed string and to increase the expression *array[i] inside the while loop.
Also it is better when the function has the return type size_t (size_t is the type that is returned by the standard C function strlen and by the operator sizeof)
The function can look as it is shown in the demonstrative program.
#include <stdio.h>
size_t countChars( const char *array[], size_t n )
{
size_t count = 0;
while ( n-- )
{
if ( array[n] )
{
size_t i = 0;
do { ++count; } while ( array[n][i++] );
}
}
return count;
}
int main(void)
{
const char * example[] = { "s", "ss", "sss" };
printf( "%zu\n", countChars( example, sizeof( example ) / sizeof( *example ) ) );
return 0;
}
The program output is
9
Each element of this array
char *example[] = {"s", "ss", "sss"};
has type char * and is a pointer to the first character of the corresponding string literal.
Since your array contains string constants you should declare it with const:
const char *example[3];
Without const the compiler will not warn you if you try to assign a character to example[i][j]. For the same reason the formal parameter should also be declared with const.
For a pure function with no side effects it is better to name it so that it reflects the result. Therefor I would use charCount instead of countChars (or maybe totalLength). The focus should be on a noun (namely count or length).
Here is my solution:
#include <stdio.h>
#define LEN(a) (sizeof (a) / sizeof (a)[0])
static int CharCount(const char *strings[], int len)
{
int result, i, j;
result = 0;
for (i = 0; i < len; i++) {
j = 0;
while (strings[i][j] != '\0') {
result++;
j++;
}
}
return result;
}
int main(void)
{
const char *strings[] = { "s", "ss", "sss" };
printf("character count: %d\n", CharCount(strings, LEN(strings)));
}
The length macro LEN is very convenient and is the least error prone way to handle array lengths.
Yes char *array[] = {"aa", "bb", "cc"} is an array of pointers to strings.
array[0] points to "aa"
array[1] points to "bb"
array[2] points to "cc"
You probably want this:
int countChars(char *array[], int len)
{
int count = 0;
for (int arrayindex = 0; arrayindex < len; arrayindex++)
{
const char *stringptr = array[arrayindex];
// stringptr will point successively
// to "s", to "ss" and to "sss"
while (*stringptr++)
count++; // increment count until NUL character encountered
count++; // one more for NUL character
}
return count;
}
int main() {
char *example[] = { "s", "ss", "sss" };
int x = countChars(example, 3); // x contains 9 after the call to countChars
// that is 2 + 3 + 4
}
Instead of hard coding 3 you could use sizeof(example) / sizeof(example[0]).

Print sorted strings from array of strings

I need help with the following program:
Print all sorted strings from the input array of strings.
Assume that strings are sorted if characters are in lexicographic order (also assume that the only characters in strings are letters).
Example:
INPUT:
n=2
1. string: stack
2. string: exchange
OUTPUT:
No sorted strings
I am having a problem with accessing some variables in the following program:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 30
char** read(int *pn);
int isSorted(char *str);
char** sortedArr(char **str,int pn);
char** read(int *pn)
{
do
{
printf("n = ");
scanf("%d",pn);
}
while(*pn < 1);
char **arr;
arr=(char **)malloc(*pn * sizeof(char *));
int i;
for(i=0; i<*pn;i++)
arr[i]=(char *)malloc(MAX+1);
for(i=0; i<*pn; i++)
{
printf("%d. word: ",i+1);
scanf("%s",arr[i]);
}
return arr;
}
int isSorted(char *str)
{
int i,j;
for(i=0; i<strlen(str)-1;i++)
for(j=i+1; j<strlen(str); j++)
if(strcmp(str+i,str+j) > 0)
return 1;
return 0;
}
char** sortedArr(char **str,int pn)
{
char **sortArr;
sortArr=(char **)malloc(pn * sizeof(char *));
int i;
for(i=0; i<pn; i++)
{
if(isSorted(sortArr[i]))
sortArr[i]=(char *)malloc(MAX+1);
}
for(i=0; i<pn; i++)
{
if(isSorted(sortArr[i]))
printf("%d. word: %s",sortArr+i);
}
return sortArr;
}
int main()
{
char **arr;
char **sortArr;
int pn;
arr=read(&pn);
sortArr=sortedArr(arr,pn);
int i;
for(i=0; i<pn; i++)
free(arr[i]);
free(arr);
return 0;
}
The problem is how to access the variable pn in function sortedArr()?
Your program has several issues, I'll try to address the most part of them.
Let's start from the isSorted function, if your goal is to check if a word has all the character sorted, you don't need to use strcmp or a nested loop. All what you need is something like this:
// check if all the character in the string are sorted
int isSorted( char *str )
{
int i, length = strlen(str) - 1;
for ( i=0; i < length; i++ )
if ( str[i] > str[i+1] )
return 0;
return 1;
}
I'll separate the printing function from the input one and copy ones, so to have:
void print( char **str, int n )
{
int i;
for ( i = 0; i < n; i++ ) {
printf("word %d: %s\n", i + 1, str[i]);
}
}
There are several methods to read some words from stdin and some are presented in other answers. I'll use this, but you should check all the pointers returned from malloc:
char** read(int *pn)
{
char buffer[BUFSIZE];
printf("Please, enter number of words: ");
while ( *pn < 1 && fgets(buffer, BUFSIZE, stdin) ) {
sscanf(buffer, "%d", pn);
}
int i = 0, length;
printf("\nPlease, enter the words: \n");
char **arr = malloc(*pn * sizeof(char *));
while ( i < *pn ) {
// read words one line at a time
if ( !fgets(buffer, BUFSIZE, stdin) )
break;
length = strlen(buffer);
// ignore empty lines
if ( length < 2 )
continue;
arr[i] = malloc(length);
memcpy(arr[i],buffer,length);
// add the null terminator
arr[i][length - 1] = '\0';
++i;
}
*pn = i;
return arr;
}
Then, I'm not really sure if you want only to print the words that are "sorted" or you actually need to copy them (and print later). I'll show you the latter:
// return an array of string containing only the sorted ones
char** sortedArr( char **str, int n, int *m)
{
char **sortArr = NULL;
char *sorted = calloc(n,1);
int i;
*m = 0;
// first find (and count) the sorted strings
for ( i = 0; i < n; i++ ) {
if ( isSorted(str[i]) ) {
// maybe you need only to print str[i] now...
sorted[i] = 1;
++(*m);
}
}
// then copy the sorted. I'm not sure if you need this
int j = 0, length = 0;
if ( *m ) {
sortArr = malloc(*m * sizeof(char *));
for ( i = 0; i < n; i++ ) {
if ( !sorted[i] )
continue;
length = strlen(str[i]) + 1;
sortArr[j] = malloc(length);
memcpy(sortArr[j],str[i],length);
}
}
free(sorted);
return sortArr;
}
Finally the main function (and the one to free allocated memory):
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define BUFSIZE 128
char** read( int *pn );
int isSorted( char *str );
char** sortedArr( char **str, int n, int *m );
void print( char **str, int n );
void freeArr( char **str, int n );
void freeArr( char **str, int n )
{
if ( !str ) return;
int i;
for ( i = 0; i < n; i++ ) {
free(str[i]);
}
free(str);
}
int main()
{
char **arr = NULL;
char **sortArr = NULL;
int n = 0, m = 0;
arr = read(&n);
print(arr, n);
printf("\nSorted: \n");
sortArr = sortedArr(arr,n,&m);
print(sortArr, m);
freeArr(sortArr, m);
freeArr(arr, n);
return 0;
}
Hope it helped. Tell me if there is something wrong or I have misunderstood your task.
Change the sortedArr function, so that it takes pn as an argument:
char** sortedArr(char **str, int pn)...
Then, in your main(), change the sortArr=sortedArr(arr) to sortArr=sortedArr(arr, pn), to pass the value to the function. Then you can use the pn value inside the sortedArr function.
One head-scratcher is:
for(i=0; i<*pn;i++)
arr[i]=(char *)malloc(strlen(arr+i)+1);
for(i=0; i<*pn; i++)
{
printf("%d. word: ",i+1);
scanf("%s",arr[i]);
}
You should combine both because you cannot allocate properly until you know the length of word. Allocating some strlen(arr+i)+1 for who knows what is at arr+i is meaningless (and unless arr+i just happens to be a nul-terminated string, undefined behavior). When you are taking input, you can/should use a temprory buffer to hold the input until you can validate it is what you want it to be. At minimum, test the return to scanf to insure you actually had a sucessful conversion to the type of input you are expecting. For instance:
for (i = 0; i < *pn; i++)
{
char buf[64] = ""; /* however long is sufficient for word */
printf ("%d. word: ",i+1);
if (scanf ("%63[^\n']%*c",buf) == 1)
arr[i] = strdup (buf); /* allocates/copies buf for arr[i] */
else {
fprintf (stderr, "error: invalid input for word[%d].\n", i);
}
}
(note: you have similar allocation issues in sortedArr)
For your sort, you need to pass pn as a parameter to sortedArr so you at least know how many strings you are dealing with. Rather than looping and attempting to compare adjacent elements, why not have your sortedArr function simply call qsort and sort the array you create in read. If you want to preserve both the original and sorted arrays, then have sortedArr call memcpy and create a copy of arr and then call qsort on the copy. All you need to do is create a string comparison compare function for qsort to compare arr or the copy, e.g.:
/* comparison function for qsort (char **) */
int cmp_str (const void *a, const void *b)
{
/* The actual arguments to this function are "pointers to
pointers to char", but strcmp(3) arguments are "pointers
to char", hence the following cast plus dereference
note: to reverse sort order, swap a and b, below */
return strcmp (* (char * const *) a, * (char * const *) b);
}
Which you can then use to sort your arr (or copy) with
qsort (arr, pn, sizeof *arr, cmp_str);
Much less error-prone then a one-off loop and index attempt. Give it a try and let me know if you have questions.

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

Resources