Array pointer issue in C - array only contains last value - c

I'm trying to add (well, append really) the letters in the alphabet to an empty char array. However, I appear to run into some sort of pointer issue I don't understand, as my array contains only the last character. I tried moving the letter char outside of the for loop, but the compiler didn't like that. I also looked on here about how to create a list of all alphabetical chars, and one of the better answers was to type them all in 1 at a time. However, my problem means I don't fully understand for loops and pointers in C, and I want to.
#include <stdio.h>
int main(void) {
char *empty_list[26];
for (int i = 0; i < 26; i++){
char letter = i + 65;
empty_list[i] = &letter;
}
printf("%s", *empty_list);
return 0;
}

The main problem is your declaration:
char *empty_list[26];
defines an array of 26 pointers to characters. In your current code you assign each element in the array the address of the variable letter. Since that is out of scope when you print it is luck that it prints out the last one, it could equally have printed out garbage or crashed if the code between was complex. It could also have printed out additional garbage after the letter with what you already have since there is no way of knowing whether there is a string terminating character (\0) after the letter. In your existing code printf("%s", *empty_list); prints the first pointer from the array as a null terminated string, which if you ignore the loss of scope and assume the memory contents are still around, will be the last value from the loop since all pointers in your array point to the memory that letter was stored at and that memory has the last value from the loop.
If your intention was to create an array with the letters then it should be:
char empty_list[27];
It needs to be 27 as you need to leave space for the string terminating character at the end. One way to fill that in would be to use:
empty_list[26] = '\0';
after the end of your for loop and before you print the contents of the array (do not include the asterisk here - because it is an array the compiler will automatically take the address of the first element):
printf("%s", empty_list);
As brothir mentioned in the comments when you assign the value of the letter to the element in the array it should be without the ampersand:
empty_list[i] = letter;

There are a few things wrong with your code.
Firstly, the type of empty_list is presently an array of pointers to char, when it really should be an array of char, since your intent is to print it out as if it were the latter in the call to printf after your loop. char empty_list[26]; is the correct declaration.
Secondly, in your loop, you assign &letter when all you need is letter. Heck, you don't even need the intermediate variable letter. Just empty_list[i] = i + 'A'; will suffice.
Lastly, you are passing empty_list to printf to satisfy a format specifier %s, which expects a null-terminated string. What you need to do is add another element to empty_list and set that to zero:
char empty_list[27];
// populated 0..25 with 'A'..'Z' in your code...
empty_list[26] = '\0';
printf("%s\n", empty_list);
// Output: ABC...Z

With the above help (much appreciated), my working code to create an array of letters in C is below:
#include <stdio.h>
int main(void) {
// create an array with 1 extra space for null terminator
char empty_list[27];
// add null terminator so string knows when it's finished.
empty_list[26] = '\0';
for (int i = 0; i < 26; i++){
// add 65 to get ASCII value for 'A'
char letter = A + i;
// insert each char into the array sequentially
empty_list[i] = letter;
}
printf("%s", empty_list);
return 0;
}

Related

How do I print the contents of an array of strings?

I have created and initialized an array with the following strings:
char print_names[][10] = {"\t\t1. John\n",
"\t\t2. Smith\n",
"\t\t3. Jane\n",
"\t\t4. Mary\n",
"\t\t5. Lisa\n"};
As far as I know, the name of the array is a pointer itself. so when I put these lines:
printf("%c", *print_names[0]);
printf("%c", *print_names[1]);
It should point to the content of the that array element. But nothing is printed out on the console.
I went into the debugger and it clearly shows that each element holds the appropriate string. I'm not sure where I did wrong.
EDIT: I'm still learning the basic about array and pointer, so I didn't include <string.h> in the file.
Additional question: is it possible to print the content (the names) without using string?
OK. I figured it out. I think I understand now. Thanks for answering.
*print_names[0] is equal to print_names[0][0]. It's the first character of the first string in print_names.
And as the first character of every string in the print_names array is a tab ('\t') you print this tab which isn't really visible.
If you want to print the string itself you need to use %s as the format, and pass a pointer to the first character. Which can be done as:
printf("%s", print_names[0]);
On the other hand, if you want to print the tab, and make it seen, then surround the output with other characters. Like
printf("tab = \"%c\"\n", print_names[0][0]);
which will print the tab surrounded by double quotes.
The array print_names has 2 dimensions:
the number of elements is determined from the initializer: 5 in your example
the number of char elements in each element in the array is defined to 10.
The problem is 5 of the initializers have exactly 10 characters and one has 11 characters. The initializer is inconsistent with the object definition and none of the elements are null terminated strings.
You should change the width to at least 12 and you can use printf() to print the array elements this way:
#include <stdio.h>
void print_array() {
char print_names[][12] = {
"\t\t1. John\n",
"\t\t2. Smith\n",
"\t\t3. Jane\n",
"\t\t4. Mary\n",
"\t\t5. Lisa\n"
};
size_t count = sizeof(print_names) / sizeof(print_names[0]);
for (size_t i = 0; i < count; i++) {
printf("%s", print_names[i]);
}
}
Regarding your approach:
As far as I know, the name of the array is a pointer itself.
Not really: the name of the array just that. When you use the name of an array in an expression other than sizeof(n), it decays into a pointer to the first element of the array.
The lines below output the first byte of the first and second strings:
printf("%c", *print_names[0]); // same as print_names[0][0]
printf("%c", *print_names[1]); // same as print_names[1][0]
As you have overdimensioned the array (with 10 entries, but you have only filled 5, the others are filled with NULL pointers) you can print the array contents (one string per line) with:
char **p;
for (p = print_names; *p; p++)
printf("%s", *p);
which is equivalent to this code:
int i;
for (i = 0; print_names[i]; i++)
printf("%s", print_names[i]);
of if you know that there are 5 elements in the array:
int i;
for (i = 0; i < 5; i++)
printf("%s", print_names[i]);
It works ,but because the first element of each row is \t you won't see any thing you can also use
printf("%s", print_names[0])
to print : \t\t1. John\n
this row.
notice you're placing more than 10 characters in second dimension of your array.

Why don’t we need for loop to print strings in C?

I don't understand Why don’t we have to print strings in for loop ? In normal cases we need to print arrays in for loop. For example, if we want to print the array of integers. It will be like this:
int a[n];
for (i = 0; i < n; i++){
printf("%d", a[i]);
}
But for strings like:
char s[100] = " Hello ";
printf("%s\n", s);
it is enough to write the name of array.
EDIT: It seems like I didnt ask my question properly as some of you wrote answers which is not related to my question.I edit my question.
Strings terminate with the empty character '\0', that's how it is possible to know when a string ends even without explicitly passing its length.
The difference is that C-style strings (which are char arrays) are zero-terminated, whereas int arrays are normally not zero terminated.
Theoretically, you could also create an int array which is zero-terminated and print that in a loop:
int a[] = {5,7,3,0};
for (i=0;a[i]!=0;i++)
{
printf("%d",a[i])
}
However, the problem with zero-terminated int arrays is that the number 0 could be a meaningful value, so you cannot be sure that it really is the end of the array when you encounter that value. With strings, however, the ASCII-Code 0 does not represent a meaningful value, so you can be reasonably sure that you have reached the end of the string.
Your example is far from analogous. %d refers to a single integer, while %s refers to an entire (but still single) string.
You are not passing the size of the array n[] to printf either - rather you are calling printf n times. You are printing one int just as you are printing one string.
The actual string length is not known a priori, rather printf iterates the string until it encounters the \0 terminator. Equivalent to:
for( int i = 0; s[i] != '\0'; i++)
{
printf( "%c", s[i] ) ;
}
because
char s[100] = " Hello ";
is equivalent to:
char s[100] = { ' ', 'H', 'e', 'l', 'l', 'o', ' ', '\0' } ;
Strings are multiple characters all at once. You cannot ask for a specific character from a string. If you want to do so, you must refer to it as an array of chars like this
for (i = 0; i < n; i++){
printf("%c", s[i]);
}
It is because you are already providing the parameter which is "%s" to the printf function which already has a definition telling it how to print a string.
Hope it helps.
One of the reason is that char only takes 1 byte of memeory and when you just press a character, the first index of array is filled up completely and it moves on to the next one till it encounters NULL character. This is not the case with integer array where the size is more than 1 byte and is machine dependent. So you cannot escape the first index by just pressing the number less than the maximum range. If you try to do this, it will store your numbers in first index only and hence a for loop is required there.

Array showing random characters at the end

I wanted to test things out with arrays on C as I'm just starting to learn the language. Here is my code:
#include <stdio.h>
main(){
int i,t;
char orig[5];
for(i=0;i<=4;i++){
orig[i] = '.';
}
printf("%s\n", orig);
}
Here is my output:
.....�
It is exactly that. What are those mysterious characters? What have i done wrong?
%s with printf() expects a pointer to a string, that is, pointer to the initial element of a null terminated character array. Your array is not null terminated.
Thus, in search of the terminating null character, printf() goes out of bound, and subsequently, invokes undefined behavior.
You have to null-terminate your array, if you want that to be used as a string.
Quote: C11, chapter §7.21.6.1, (emphasis mine)
s
If no l length modifier is present, the argument shall be a pointer to the initial element of an array of character type.280) Characters from the array are
written up to (but not including) the terminating null character. If the
precision is specified, no more than that many bytes are written. If the
precision is not specified or is greater than the size of the array, the array shall
contain a null character.
Quick solution:
Increase the array size by 1, char orig[6];.
Add a null -terminator in the end. After the loop body, add orig[i] = '\0';
And then, print the result.
char orig[5];//creates an array of 5 char. (with indices ranging from 0 to 4)
|?|?|?|0|0|0|0|0|?|?|?|?|
| ^memory you do not own (your mysterious characters)
^start of orig
for(i=0;i<=4;i++){ //attempts to populate array with '.'
orig[i] = '.';
|?|?|?|.|.|.|.|.|?|?|?|?|
| ^memory you do not own (your mysterious characters)
^start of orig
This results in a non null terminated char array, which will invoke undefined behavior if used in a function that expects a C string. C strings must contain enough space to allow for null termination. Change your declaration to the following to accommodate.
char orig[6];
Then add the null termination to the end of your loop:
...
for(i=0;i<=4;i++){
orig[i] = '.';
}
orig[i] = 0;
Resulting in:
|?|?|?|.|.|.|.|.|0|?|?|?|
| ^memory you do not own
^start of orig
Note: Because the null termination results in a C string, the function using it knows how to interpret its contents (i.e. no undefined behavior), and your mysterious characters are held at bay.
There is a difference between an array and a character array. You can consider a character array is an special case of array in which each element is of type char in C and the array should be ended (terminated) by a character null (ASCII value 0).
%s format specifier with printf() expects a pointer to a character array which is terminated by a null character. Your array is not null terminated and hence, printf function goes beyond 5 characters assigned by you and prints garbage values present after your 5th character ('.').
To solve your issues, you need to statically allocate the character array of size one more than the characters you want to store. In your case, a character array of size 6 will work.
#include <stdio.h>
int main(){
int i,t;
char orig[6]; // If you want to store 5 characters, allocate an array of size 6 to store null character at last position.
for (i=0; i<=4; i++) {
orig[i] = '.';
}
orig[5] = '\0';
printf("%s\n", orig);
}
There is a reason to waste one extra character space for the null character. The reason being whenever you pass any array to a function, then only pointer to first element is passed to the function (pushed in function's stack). This makes for a function impossible to determine the end of the array (means operators like sizeof won't work inside the function and sizeof will return the size of the pointer in your machine). That is the reason, functions like memcpy, memset takes an additional function arguments which mentions the array sizes (or the length upto which you want to operate).
However, using character array, function can determine the size of the array by looking for a special character (null character).
You need to add a NUL character (\0) at the end of your string.
#include <stdio.h>
main()
{
int i,t;
char orig[6];
for(i=0;i<=4;i++){
orig[i] = '.';
}
orig[i] = '\0';
printf("%s\n", orig);
}
If you do not know what \0 is, I strongly recommand you to check the ascii table (https://www.asciitable.com/).
Good luck
prinftf takes starting pointer of any memory location, array in this case and print till it encounter a \0 character. These type of strings are called as null terminated strings.
So please add a \0 at the end and put in characters till (size of array - 2) like this :
main(){
int i,t;
char orig[5];
for(i=0;i<4;i++){ //less then size of array -1
orig[i] = '.';
}
orig[i] = '\0'
printf("%s\n", orig);
}

Printing the value of a 0-initialized array element prints nothing, why?

I have to initialize a char array to 0's. I did it like
char array[256] = {0};
I wanted to check if it worked so I tried testing it
#include <stdio.h>
int main()
{
char s[256] = {0};
printf("%c\n", s[10]);
return 0;
}
After I compile and run it, the command line output shows nothing.
What am I missing ? Perhaps I initialized the array in a wrong manner ?
TL;DR -- %c is the character representation. Use %d to see the decimal 0 value.
Related , from C11, chapter §7.21.6.1, (emphasis mine)
c If no l length modifier is present, the int argument is converted to an
unsigned char, and the resulting character is written.
FYI, see the list of printable values.
That said, for a hosted environment, int main() should be int main(void), at least to conform to the standard.
You are printing s[10] as a character (%c), and the numeric value of s[10] is 0, which represents the character \0, which means end of string and has no textual representation. For this reason you are not seeing anything.
If you want to see the numeric value instead of the character value, use %d to print it as a decimal (integer) number:
printf("%d\n", s[10]);
Note that end of string isn't the same as end of line, as said in one of your comments. End of string means that any string operation over a character sequence must stop when the first \0 arrives. If the character sequence has anything else after \0, it won't be printed, because the string operation stops on the first \0 character.
An end of line is, however, a normal character, which visual effect is to say the terminal or text editor to print the next character after the end of line in a new line.
If you want to have a vector full of end of line characters (and print them as such), you have to travel the vector and fill it:
char s[256];
int i;
for (i = 0; i < 256; ++i)
s[i] = '\n';
printf("%c\n", s[10]);
The ASCII (decimal/numerical) value of the end of line character (\n) is 12, so, the following snippet will be equivalent:
char s[256];
int i;
for (i = 0; i < 256; ++i)
s[i] = 12;
printf("%c\n", s[10]);
That doesn't work however (it doesn't print a new line):
char s[256] = {'\n'}; // or {12};
printf("%c\n", s[10]);
because the effect of {'\n'} is to assign \n to the first element of the array, and the remainings 255 character are filled with value 0, no matter which type of array are you making (char[], int[] or whatever). If you write an empty pair of brackets {}, all the elements will be 0.
So, these two statements are equivalent:
char s[256] = {}; // Implicit filling to 0.
char s[256] = {0}; // Implicit filling to 0 from the second element.
However, without defining the array:
char s[256];
The array is not filling (not initialized), so, each element of s will have anything, until you fill it with values, for example, with a for.
I hope with all of this examples you get the whole picture.

How to check each character in a dynamically allocated string array, in C?

So what I am trying to ultimately do is search an array for a name, and if the name is found return that name. Well, to do that I need to check for each character in every row and column for a match. And before I could do that I need to know exactly how to go about doing that, so I am trying to figure out how to get the dynamic array to print out the first character, then second and so on in order to compare it with the name being searched. But I am having trouble doing this. So my question is how would I go about checking each character in such an array? I've let out most parts of the code but I think I included the main parts that I am troubled in. Thanks for the help in advance.
I'm a beginner in C, so sorry if I did anything gravely wrong, thanks!
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define STRINGSIZE 20
int main(){
char **firstNames, **lastNames;
int classSize,i;
char sample[21] = "Slack";
printf("Please indicate number of records you want to enter (min 5, max 15):\n");
scanf("%d", &classSize);
firstNames=malloc(classSize*sizeof(char*));
for (i=0; i<classSize; i++) {
firstNames[i]=malloc(STRINGSIZE*sizeof(char));
}
printf("Please input records of students (enter a new line after each record), with following format: first name");
*firstNames="Slack";
printf("\n\n");
printf("%c", *(sample)); //Will print out S
printf("%c", **firstNames); //Will print out S
printf("%c", *(sample+1)); //Will print out l
printf("%c", **(firstNames+1)); //Will give error
printf("%c", **(firstNames)+1); //Will print T (Next ascii char after 'S'
printf("%c", **((firstNames)+1)); //Will give error
}
A C string is an array of characters. Even if dynamically allocated, you can treat it as such, so:
sample[0]; // S
sample[1]; // l
sample[2]; // a
// etc
You are storing multiple pointers to C strings in firstNames. You access it as an array:
firstNames[0]; // first name
firstNames[1]; // second name
firstNames[2]; // third name
// etc.
Now you just combine these, as firstName[0] is just a C string, just like sample:
firstName[0][0]; // first letter in first name
firstName[0][1]; // second letter in first name
firstName[1][0]; // first letter in second na,e
// etc.
You have an array of pointers to char firstNames the size of classSize. Every pointer in this array points to valid memory you allocated with malloc.
The error you make is assigning a string literal to the first pointer of the array firstNames, overwriting the pointer with the address of the string literal. This will lose the memory you allocated and also the string literal cannot be modified, which you do later causing the program to crash.
This line will copy a string "Slack" to the memory the first pointer in the array points to:
strcpy( firstNames[0] , "Slack" ) ; //make sure you have enough space
Note that firstNames[0] equals to *firstNames.
i used in the for loop is not defined anywhere.

Resources