I'm learning C programming and I'm having some issues to print a name that i store in a char array.
char nameArr[125];
for (int i = 0; i < 125; i++)
{
if (nameArr[i] != "\0")
{
printf(nameArr[i]);
}
else
{
i = 125;
}
}
This is my code in which I try to print out a name like "Joe Doe" that I already stored in the char array, but I get some errors in the compiler when I run this.
If I'm not suppose to do like this, how can I print out just the name and not all the 125 slots of the array?
Assuming your nameArr already contains a string, which is defined as a sequence of characters ending with 0, the obvious solution is to do
printf("%s", nameArr);
or
puts(nameArr); // appends newline automatically
If your question is how you would do this by hand, it would look something like this:
for (size_t i = 0; nameArr[i]; ++i)
{
putchar(nameArr[i]);
// or printf("%c", nameArr[i]);
}
nameArr[i] evaluates as true as long as this isn't a 0 byte. Also, always use size_t for array indices. int is not guaranteed to hold any size an object in C can have.
Related
I just started learning C language and I need some help with a program. Here is the code.
Questions:
What is this? customerData[NUM_FIELDS][FIELD_LENGTH];
Is it a char 2D array?
How do you input data into the array? fgetC, putchar, getchar ?
#include <stdio.h> #include <string.h> #include <stdlib.h>
#define INPUT_LENGTH 128
#define FIELD_LENGTH 30
#define NUM_FIELDS 9
int main()
{
FILE *data=NULL;
char input[INPUT_LENGTH];
char customerData[NUM_FIELDS][FIELD_LENGTH];
int element=0;
char *next;
char ch;
data= fopen("data.txt","r");
if(data!=NULL)
{
//token=strtok(input,"|");
/*while loop will go through line by line and stored it in an input array*/
while(fgets(input,INPUT_LENGTH,data)!= NULL)
{
next=strtok(input,"|");
while(next!=NULL)
{
//ch=getchar()
//>probably a get char for ch
strcpy(next,customerData[element][strlen(next)]);
/*need to put the values into customer data one by one*/
printf("%s\n",next);
//element+=1;
next=strtok(NULL,"|");
}
//element=0;
}
printf("program is done\n");
}
fclose(data);
return 0;
}
In general, "help me with my code" questions are off-topic on Stack Overflow. In order to keep the question on-topic, I'm going to focus only on the question of how to access 2D char arrays.
Yes, this is a 2D char array. Or, put another way, it's an array with NUM_FIELDS elements, where each element of the array is a char array with FIELD_LENGTH elements.
There are loads of ways to insert data into a 2D char array, but there are probably two I've encountered most often. Which one you choose to use will depend on how you want to think of this array.
Option 1: A 2D array of single chars
The first way to think about this variable is simply as a 2D array of chars - a grid of elements that you can access. Here, you can simply input values using the normal assignment operator. You'll want to make sure that your indexes are in range, or you'll start accessing invalid memory.
//Set a known element that's definitely in range
customerData[1][2] = 'A';
//Loop through all the elements
for(int ii = 0; ii < NUM_FIELDS; ii++)
{
for (int jj = 0; jj < FIELD_LENGTH; jj++)
{
customerData[i][j] = 'B';
}
}
//Set an element from variables
char nextInput = getNextCharFromInput();
if(x < NUM_FIELD && y < FIELD_LENGTH)
{
customerData[x][y] = nextInput;
}
//Bad. This could corrupt memory
customerData[100][60] = 'X';
//Risky without check. How do you know x and y are in range?
cusomterData[x][y] = 'X';
You could certainly write your code by assigning these elements on character at a time. However, the broader context of your program heavily implies to me that the next option is better.
Option 2: A 1D array of fixed-length strings
In C, a "string" is simply an array of chars. So another way to look at this variable (and the one that makes the most sense for this program) is to treat it as a 1D array of length NUM_FIELDS, where each element is a string of length FIELD_LENGTH.
Looking at this this way, you can start using the C string functions to input data into the array, rather than needing to deal character by character. As before, you still need to be careful of lengths so that you don't go off the end of the strings.
Also be aware that all array decay into pointers, so char* is also a string (just of unknown length).
//Set a specific field to a known string, which is short enough to fit
strcpy(customerData[2], "date");
//Loop through all fields and wipe their data
for(int ii = 0; ii < NUM_FIELDS; ii++)
{
memset(customerData[ii], 0, FIELD_LENGTH);
}
//Set field based on variables
if(x < NUM_FIELDS)
{
//Will truncate next if it is too long
strncpy(customerData[x], next, FIELD_LENGTH);
//Will not input anything if field is too long
if(strlen(next) < FIELD_LENGTH)
{
strcpy(customerData[x], next);
}
}
//Bad. Could corrupt memory
strcpy(customerData[100], "date");
strcpy(customerData[1], "this string is definitely much longer than FIELD_LENGTH");
//Risky. Without a check, how do you know either variable in in range?
strcpy(customerData[x], next);
getchar and fgetC both deal with reading characters, from stdout and a file respectively, so can't be used to put data into a variable. putchar does deal with put character into things, but only stdout, so can't be used here.
I have one long array, and I'm trying to figure out how to split it up into two separate arrays, the second array has the right contents but the first is empty, I'm also getting an Abort Trap:6 and I'm not sure what that means.
I have an array called entireA, which looks something like this:
HELLO:WORLD, I want to put HELLO in a separate array (firstA) and WORLD in secondA. When I print first and second array at the end, secondA has the right contents but firstA doesn't event though I'm printing to check if the right characters are being passed over and they are -- but the firstA is still empty and I'm getting and abort trap i don't understand.
I've just started learning C, why is the first array empty and what does the error mean?
#define ARRSIZE 10000
char entireA[ARRSIZE] = "";
char firstA[ARRSIZE] = "";
char secondA[ARRSIZE] = "";
strcpy(entireA,"HELLO:WORLD\n");
int firstVar = 0;
int entireVar = 0;
while(entireA[entireVar] != ':') {
if(entireA[entireVar] == ';') {
break;
}
printf("%c \n",entireA[entireVar]);
firstA[firstVar] = entireA[entireVar];
firstVar++;
entireVar++;
}
firstA[firstVar] = '\0';
int secondVar = 0;
entireVar++; //skip ':'
while(entireA[entireVar] != '\n') {
secondA[secondVar] = entireA[entireVar];
secondVar++;
entireVar++;
}
secondA[secondVar] = '\0';
printf("%s", firstA);
printf("%s", secondA);
There is nothing wrong with the code you posted.
After execution, the variables have the following values:
entireA 0x02efcdb4 "HELLO:WORLD\n" char[0x00002710]
entireVar 0x0000000b int
firstA 0x02efa69c "HELLO" char[0x00002710]
firstVar 0x00000005 int
secondA 0x02ef7f84 "WORLD" char[0x00002710]
secondVar 0x00000005 int
Whatever your problem is, it's most likely something to do with your environment. I would suggest reducing the value of ARRSIZE to, say 80 characters, and seeing if that changes your results.
Say I have a birthday that is written as 04251993 in some file that
I want to format it as 04/25/1993
I'm assuming that I should make an empty string, or modify the old string into the new string.
I'm not quite sure of how to do that: need some help on writing the function.
I started it out like this.
the first two chars need to be the month with a slash after, 2 more chars with a slash after and then lasty 4 more chars to put out the year.
void timef(char str[]){
printf("%c, str[0]) ?
Make a character array large enough on the heap. Then go through the
characters and insert the slashes. Use fputs to place it in a file. Repeat.
Use "%.*s" to scan the original string and then write to a new one
const char *src = "04251993";
char dest[11];
if (strlen(src) >= 8) {
sprintf(dest, "%.2s/%.2s/%.4s", src, src + 2, src + 4);
}
You can either write a function that is general or one that only performs an operation within set bounds. For this answer, let's just work on the latter. This means, I'll assume your string is always a fixed size of 9 chars (including '\0') and the packing of the data is "mm/dd/yyyy".
From there, you just need to work out how much larger the new string needs to be, and that's originalString + 2 chars, so you need a new array of 11 characters.
char newDate[11] = "";
Then you need to loop through the contents of the original string array and place each character into the new array, as well as adding the slashes as you go. So something like this:
int main()
{
int newSize = 11;
char oldDate[9] = "04231993";
char newDate[11] = "";
for(int i = 0, j = 0; i < newSize && j < oldSize; i++, j++){
if(i == 2){
newDate[i] = '/';
i++;
}
if(i == 5){
newDate[i] = '/';
i++;
}
newDate[i] = oldDate[j];
}
printf("%s", newDate);
}
That's REALLY simple and only to illustrate the basic concept. I would recommend working on your own, more robust version.
I have a char array LL,4014.84954 that I send into a function like this example:
#include <stdio.h>
#include <math.h>
void myFunction(char* in_string, char* out_string) {
printf("Start_String=%s\n", in_string);
int in_size = (int)(sizeof(in_string));
printf("%d\n", in_size);
int i = 0;
for(i = 0; i <= in_size-ceil(in_size/2); i++) {
out_string[i] = in_string[i];
}
}
int main(int arg) {
char in_string[] = "LL,4014.84954";
char out_string[] = "";
printf("In_String=%s\n", in_string);
myFunction(in_string, out_string);
printf("Out_String=%s\n", out_string);
}
My question has two parts.
How do I get the length of this char array? int in_size = (int)(sizeof(in_string)); in this example gives me 8 which is the size of the pointer (long int). I know I could make a for loop that marches through until it see the null termination, but is there a nicer way? I previously was using char[] and sizeof works great, but now I am converting to char*.
How can I write a portion of these chars to out_string. My example currently writes all chars to out_string.
Here is the raw output:
In_String=LL,4014.84954
Start_String=LL,4014.84954
8
Out_String=LL,40014.84954
(1)
Answer to question 2:
char out_string[] = "";
out_string[] is of only one size. you assigning out_string[i] = ... for i > 0 is wrong and cause an undefined error. Instead of this you should declare out_string[] like this:
out_string[] = malloc(strlen(in_string) + 1);
// ^ extra for \0 char
(2)
additionally #WhozCraig commenting correct, you actually need strlen() to find length of string. sizeof you are using wrong.
So replace:
int in_size = (int)(sizeof(in_string));
by
int in_size = strlen(in_string);
(3)
Also, what is in_size-ceil. As I can understands from your raw output you don't need such kind of function and calculations. Just replace your for loop:
for(i = 0; i <= in_size-ceil(in_size/2); i++)
by
for(i = 0; i < in_size; i++)
(4)
At the end don;t forget to terminate you string out_string, after for loop add this line
out_string[i] = '\0'
Regarding your first question, use strlen().
Regarding the second question, first of all you need to make sure that out_string is wide enough to accommodate the result. Currently, it isn't, and the behaviour of your code is undefined. Once you fix that, to copy a portion of the string you'd need to change the initial and final conditions of the for loop, not forgetting about the NUL terminator.
so I'm using C, I cant seem to get this to work right. It's an array of pointers to structs which contain some contact info. I can't seem to get the qsort to sort correctly.
Here is my code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 20
#define ELEMENTS 50
int sortZips(const void *a, const void *b);
typedef struct contactInfo {
char name[MAX];
char street[MAX];
char cityState[MAX];
char zipCode[MAX];
} contacts;
int main() {
int i = 0;
contacts **contactArray = malloc(ELEMENTS * sizeof(contacts *));
/* allocate array */
for (i = 0; i < ELEMENTS; i++) {
contactArray[i] = malloc(sizeof(contacts));
}
/* populate array */
for (i = 0; i < ELEMENTS; i++) {
fgets(contactArray[i]->name,MAX,stdin);
fgets(contactArray[i]->street,MAX,stdin);
fgets(contactArray[i]->cityState,MAX,stdin);
fgets(contactArray[i]->zipCode,MAX,stdin);
printf("%s", contactArray[i]->name);
printf("%s", contactArray[i]->street);
printf("%s", contactArray[i]->cityState);
printf("%s", contactArray[i]->zipCode);
}
printf("\n");
/* qsort((void *)contactArray, ELEMENTS, sizeof(contacts *), sortZips); */
for (i = 0; i < ELEMENTS; i++) {
fputs(contactArray[i]->name,stdout);
fputs(contactArray[i]->street,stdout);
fputs(contactArray[i]->cityState,stdout);
fputs(contactArray[i]->zipCode,stdout);
}
}
/* sortZips() sort function for qsort */
int sortZips(const void *a, const void *b) {
const contacts *ia = *(contacts **)a;
const contacts *ib = *(contacts **)b;
return strcmp(ia->zipCode, ib->zipCode);
}
The output is printing the addresses (I have 50 in an input file) and then some random characters, like a huge block of them, then the sorted list after that which is messed up and not sorted right.
Please any help would be appreciated. I need to learn what's wrong here and why.
Thanx.
First rule: always check input functions - in this case, fgets(). You don't know whether everything is working correctly or not if you do not check.
Second: use enum in preference to #define in general.
With the check for early EOF in place, your code sorted my sample data (6 rows) cleanly. It also compiled cleanly - which is very unusual (that's a compliment; I use stringent warnings and even my code seldom compiles cleanly the first time). My amended version of your code is very similar to yours:
int main(void)
{
int i = 0;
int num;
contacts **contactArray = malloc(ELEMENTS * sizeof(contacts *));
/* allocate array */
for (i = 0; i < ELEMENTS; i++)
contactArray[i] = malloc(sizeof(contacts));
/* populate array */
for (i = 0; i < ELEMENTS; i++)
{
if (fgets(contactArray[i]->name,MAX,stdin) == 0 ||
fgets(contactArray[i]->street,MAX,stdin) == 0 ||
fgets(contactArray[i]->cityState,MAX,stdin) == 0 ||
fgets(contactArray[i]->zipCode,MAX,stdin) == 0)
break;
printf("%s", contactArray[i]->name);
printf("%s", contactArray[i]->street);
printf("%s", contactArray[i]->cityState);
printf("%s", contactArray[i]->zipCode);
}
printf("\n");
num = i;
qsort(contactArray, num, sizeof(contacts *), sortZips);
for (i = 0; i < num; i++)
{
fputs(contactArray[i]->name,stdout);
fputs(contactArray[i]->street,stdout);
fputs(contactArray[i]->cityState,stdout);
fputs(contactArray[i]->zipCode,stdout);
}
return 0;
}
The data I used was trivial repetitions of sets of 4 lines like this:
First LastName7
7 Some Street
City, CA
95437
Note that the 'error checking' I do in the input is the bare minimum that 'works'. If you get an over-long line in the input, one field will not contain a newline, and the next will contain the next section of the input line (possibly all the rest, possibly not - it depends on how badly overlong the line is).
If your addresses are printing out rubbish at the end, then it's almost certainly because you haven't allocated enough space for them. Twenty characters is a little on the low side for addresses.
What's probably happening is that you have an address like:
14237 Verylongstreetname Avenue
and, when you do fgets (street,20,stdin);, only 14237 Verylongstree will be read (19 characters, leaving space for the null terminator).
And, here's the crux: the file pointer will still be pointing at the tname Avenue bit so that, when you try to read the cityState, you'll get that. And, when you try to read the zipCode, you'll get the cityState line, effectively stuffing up your sorting.
I believe that you have enough space. Because you are using fgets and your size of MAX, the strings should be cut to fit and have a terminating NUL at the end.
Two things that might be messing it up:
fgets will read from where it stopped reading if the line is too long. That will result in an address of "This is too long so", " it will be cut\n". And then the rest of the input will be all over the place.
If you do not have enough input to fill ELEMENTS items then you'll get whatever random data was in the malloc'd memory. If you were to use calloc instead, it would zero the memory for you. Although the better idea would be to use a counter of how many items were actually read, instead of assuming there will be ELEMENTS items.