The checking for NULL trick only works for NULL terminated strings. For a numeric array you'll have to pass in the size too.
void printArray(int *ptr, size_t length);
{
//for statement to print values using array
size_t i = 0;
for( ; i < length; ++i )
printf("%d", ptr[i]);
}
void printString(const char *ptr);
{
//for statement to print values using array
for( ; *ptr!='\0'; ++ptr)
printf("%c", *ptr);
}
int main()
{
int array[6] = {2,4,6,8,10};
const char* str = "Hello World!";
printArray(array, 6);
printString(str);
return 0;
}
Answer from Praetorian on Stack OverflowThe checking for NULL trick only works for NULL terminated strings. For a numeric array you'll have to pass in the size too.
void printArray(int *ptr, size_t length);
{
//for statement to print values using array
size_t i = 0;
for( ; i < length; ++i )
printf("%d", ptr[i]);
}
void printString(const char *ptr);
{
//for statement to print values using array
for( ; *ptr!='\0'; ++ptr)
printf("%c", *ptr);
}
int main()
{
int array[6] = {2,4,6,8,10};
const char* str = "Hello World!";
printArray(array, 6);
printString(str);
return 0;
}
You have several options:
- You could pass the size of your array into the function.
- You could have a special "sentinel" value (e.g.
-1) as the last element of your array; if you do this, you must ensure that this value cannot appear as part of the array proper.
Videos
fixing your many errors and re-editing to use strlen:
#define LENGTH 8
#include <stdio.h>
#include <string.h>
int main()
{
typedef char Arr[LENGTH];
Arr test = {'1','0','1'};
Arr* a = &test;
size_t len = strlen(test);
for(int i=0;i<len;i++){
printf("%c ", (*a)[i]);
}
}
Three problems:
- You are using
%s, which is for strings. Use%cfor characters. - You need
(*a)[i], asais a pointer to an array, so*ais an array. - 1 and 0 encode non-printable characters. So you won't see anything.
You have several errors in your code:
There is difference between variable
argvand constantdays. Variable can be changed, constant array label - cannot.In your array, terminator NULL is missing at the end of the array.
*days++;is senseless in this case. This is a dummy and returns value ofdays, and incrementdaysthereafter. It is enough to just usedays++.
Thus, your code must be like:
#include <stdio.h>
int main(void) {
char *days[] = {
"Sunday",
"Monday",
"Tuesday",
NULL
};
// Your style
char **d = days;
while ( *d ) {
printf("day is %s\n", *d);
d++;
}
// Or, more "scholastic" code
for(const char **d = days; *d; d++)
printf("day is %s\n", *d);
return 0;
The argv[] structure contains a null pointer as the last entry which is why your code works. You can add a null pointer to your data structure. You also need to realize that argv is a parameter (just like a local variable) that points to the internal data structure holding the command line arguments. You need to create a similar local variable that can iterate through the array.
Here is a solution:
#include <stdio.h>
int main(void) {
char *days[] = {"Sunday", "Monday", "Tuesday", 0 };
char **v = days;
while (v) {
printf("day is %s\n", *v);
v++;
}
return 0;
}
in printf("Loop %i: %s\n", i, %data[i]);
you are printing a char that's why %c is required and while printing % is not required
printf("Loop %i: %c\n", i, data[i]);
#include <stdio.h>
#include <stdlib.h>
char * askData() {
static char data[5];
for(i = 0; i < 5; i++)
scanf("%s", &data[i]);
return data;
}
int main() {
char* data = askData();
int i; //its better here
printf("Flag 1\n");
for(i = 0; i < 5; i++)
printf("Loop %i: %c\n", i, data[i]);
printf("Flag 2\n");
}
So you're right C doesn't return arrays in the sense that you are talking about, however the way we do that in C is by utilizing two ideas together:
Working with memory: By allocating a region of memory and then returning the starting location of that memory region.
The function call to allocate memory is called
mallocand then you have to use thefreecall to release that memory region.Pointer Arithmetic: I'm sure you already know that C has some basic types (char, int, long, float, double, and lately bool); each takes a different amount of memory and so C also provides the convenience of understanding typed pointers (pointers are variables that mark a memory location). A typed pointer understands how "big" it's associated type is in bytes and when you increment its value by 1 in C internally it's incremented by the size of the type.
Combining these ideas we can get arrays:
So for example if you have an array of five integers then you would allocate a region that is 5 * sizeof(int) ; Assuming a modern system the sizeof(int) is going to be 32-bits (or 4 bytes); so you will get a memory region of 20 bytes back and you can fill it up with the values.
#include <stdio.h>
#include <stdlib.h>
int * get_numbers(size_t count) {
int *data = malloc(count * sizeof(int));
if (!data) {
return NULL; // could not allocate memory
}
// notice that we are increasing the index i by 1
// data[i] shifts properly in memory by 4 bytes
// to store the value of the next input.
for(int i=0; i < count; i++) {
scanf("%d", &data[i]);
}
}
int main() {
int *data = get_numbers(5);
if (data == NULL) {
fprintf(stderr, "Could not allocate memory\n");
exit(-1);
}
for(int i = 0; i < 5; i++) {
printf("data[%d] = %d\n", i, data[i]);
}
free(data);
}
Now in your case you have a bit of a complication (but not really) you want to be able to read in names, which are "strings" which don't really exist in C except as array of characters.
So to rephrase our problem is that want an array of names. Each name in itself is an array of characters. The thing is, C also understands type pointer pointers (yes a pointer to pointers) and can figure out the pointer arithmetic for that.
So we can have a memory region full of different types; the type pointers themselves can have a list of pointers in a memory region; and then make sure that each pointer in that list is pointing to a valid memory region itself.
#include <stdio.h>
#include <stdlib.h>
char *get_one_name() {
char *name = NULL;
size_t len = 0;
printf("Enter a name:");
// getline takes a pointer, which if it's set to NULL
// will perform a malloc internally that's big enough to
// hold the input value.
getline(&name, &len, stdin);
return name;
}
char ** get_names(size_t count) {
// this time we need memory region enough to hold
// pointers to names
char **data = malloc(count * sizeof(char *));
if (!data) {
return NULL; // could not allocate memory
}
for(int i=0; i < count; i++) {
data[i] = get_one_name();
}
return data;
}
void free_names(char **data, size_t count) {
for(int i = 0; i < count) {
if(data[i] != NULL) {
free(data[i]);
}
}
free(data);
}
int main() {
char **data = get_names(5);
if (data == NULL) {
fprintf(stderr, "Could not allocate memory\n");
exit(-1);
}
for(int i = 0; i < 5; i++) {
printf("data[%d] = %d\n", i, data[i]);
}
free_names(data, 5);
}
Hopefully this gives some ideas to you.
Given that the code is really simple, I see mostly coding style issues with it.
Instead of this:
char *names[] = { "John", "Mona", "Lisa", "Frank" };
I would prefer either of these writing styles:
char *names[] = { "John", "Mona", "Lisa", "Frank" };
// or
char *names[] = {
"John",
"Mona",
"Lisa",
"Frank"
};
The pNames variable is pointless. You could just use names.
Instead of the while loop, a for loop would be more natural.
This maybe a matter of taste,
but I don't think the Hungarian notation like *pArr is great.
And in any case you are using this pointer to step over character by character,
so "Arr" is hardly a good name.
I'd for go for pos instead. Or even just p.
You should declare variables in the smallest scope where they are used.
For example *pos would be best declared inside the for loop.
In C99 and above, the loop variable can be declared directly in the for statement.
The last return statement is unnecessary.
The compiler will insert it automatically and make the main method return with 0 (= success).
Putting it together:
int main(int argc, char *argv[])
{
char *names[] = { "John", "Mona", "Lisa", "Frank" };
for (int i = 0; i < 4; ++i) {
char *pos = names[i];
while (*pos != '\0') {
printf("%c\n", *(pos++));
}
printf("\n");
}
}
Actually it would be more interesting to use argc and argv for something:
int main(int argc, char *argv[])
{
for (int i = 1; i < argc; ++i) {
char *pos = argv[i];
while (*pos != '\0') {
printf("%c\n", *(pos++));
}
printf("\n");
}
}
Other points not already mentioned:
Use const where possible
It's better to use const where possible so that it's clear when you are intending to modify things and clear when you're not. This helps the compiler help you find bugs early.
Avoid magic numbers
It's better to avoid having numbers like 4 in the program. If you want to change things later, you may well be left wondering "why 4? what does that mean?" Better would be to assign a constant with a meaningful name.
Use putchar rather than printf for single characters
The printf function is very useful, but putchar is often better suited for single-character output. The reason is that printf has to, at runtime, parse the format string, apply the arguments and then emit the results, while putchar only has to pass a character directly to the output. This particular code isn't exactly performance-critical but it's useful to acquire good coding habits from the beginning.
Use C idioms
It's more idiomatic C to have a loop like this for the characters:
while(*pArr) { /* ... */ }
rather than this:
while(*pArr != '\0') { /* ... */ }
Consider using a "sentinel" value for the end of a list
There are two common ways to iterate through a list in C. One is as you already have it, when you know how many values are in the list. The other way is to use a "sentinel" value -- some unique value that tells the program "this is the end of the list." For a list of names such as this program has, a rational choice for a sentinel value would be NULL.
Omit the return 0 from the end of main
Uniquely for main, if the program gets to the end of the function, it automatically does the equivalent of return 0 at the end, so you can (and should) omit it.
Result
Using all of these suggestions, one possible rewrite might look like this:
#include <stdio.h>
int main()
{
const char *names[] = { "John", "Mona", "Lisa", "Frank", NULL };
for (int i=0; names[i]; ++i) {
const char *ch = names[i];
while(*ch) {
putchar(*ch++);
putchar('\n');
}
putchar('\n');
}
}