I want to fill an array of char pointers in the following format:
[name, number of email addresses, all the email addresses]*number of people. The number of mail adresses for each person isn't known at first.
I have to use char *contacts[N]
When printing the array it only prints contacts[0], so I guess my way of scanning the input is wrong
This is my main so far:
int main()
{
char *contacts[N];
int nextAvailable = 0;
int * const nextAvailableP = &nextAvailable;
add(contacts, nextAvailableP);
//Printing this way will only print contacts[0]
int i;
for (i = 0; i < nextAvailable; i++) {
printf("%s", contacts[i]);
}
}
This is the add function:
int add(char *contacts[], int *nextAvailableP) {
if (*nextAvailableP > 97) {
printf("Not enough memory\n");
return FALSE;
}
char tempName[50];
char tempMail[50];
int numberOfMails = 1;
printf("Enter your name\n");
fgets(tempName, 50, stdin);
if ((strlen(tempName) > 0) && (tempName[strlen(tempName) - 1] == '\n'))
tempName[strlen(tempName) - 1] = '\0';
contacts[*nextAvailableP] = (char *)malloc((strlen(tempName) + 1));
if (contacts[*nextAvailableP] == NULL) {
printf("Not enough memory\n");
return FALSE;
} else {
strcpy(contacts[*nextAvailableP], tempName);
}
(*nextAvailableP)++;
int numberOfMailsIndex = *nextAvailableP;
itoa(numberOfMails, contacts[numberOfMailsIndex], 10);
(*nextAvailableP)++;
printf("Enter your mail/s, use enter to enter a mail and '-1' to signal you finished\n");
fgets(tempMail, 50, stdin);
while (strcmp(tempMail, "-1") != 0) {
if ((strlen(tempMail) > 0) && (tempMail[strlen(tempMail) - 1] == '\n')) {
tempMail[strlen(tempMail) - 1] = '\0';
}
contacts[*nextAvailableP] = (char *)malloc((strlen(tempMail) + 1));
if (contacts[*nextAvailableP] == NULL) {
printf("Not enough memory");
return FALSE;
} else {
strcpy(contacts[*nextAvailableP], tempMail);
}
(*nextAvailableP)++;
numberOfMails++;
itoa(numberOfMails, contacts[numberOfMailsIndex], 10);
fgets(tempMail, 50, stdin);
}
}
I thought I was initializing each cell in contacts to the requested size and then copying the word I scan from the user into it - but obviously I'm not. Should I iterate through each memory I've allocated char by char?
Btw, I know that the casting to *char isn't necessary
So this would be your corrected code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_ENTRIES 50
int add(char *contacts[], int *nextAvailable);
int main(void){
int i;
char *contacts[MAX_ENTRIES];
int nextAvailable = 0;
add(contacts, &nextAvailable);
add(contacts, &nextAvailable);
for(i=0; i < nextAvailable ; i++){
printf("%s\n", contacts[i]);
}
}
char* intToString(int val, int base){
//source: www.strudel.org.uk/itoa/
static char buf[32] = {0};
int i = 30;
for(; val && i ; --i, val /= base)
buf[i] = "0123456789abcdef"[val % base];
return &buf[i+1];
}
int add(char *contacts[], int *nextAvailableP) {
if (*nextAvailableP > 97) {
printf("Not enough memory\n");
return 0;
}
char tempName[50];
char tempMail[50];
int numberOfMails = 1;
printf("Enter your name\n");
fgets(tempName, 50, stdin);
if ((strlen(tempName) > 0) && (tempName[strlen(tempName) - 1] == '\n'))
tempName[strlen(tempName) - 1] = '\0';
contacts[*nextAvailableP] = (char *)malloc((strlen(tempName) + 1));
if (contacts[*nextAvailableP] == NULL) {
printf("Not enough memory\n");
return 0;
} else {
strcpy(contacts[*nextAvailableP], tempName);
}
(*nextAvailableP)++;
int numberOfMailsIndex = (*nextAvailableP);
contacts[numberOfMailsIndex] = malloc(5);
(*nextAvailableP)++;
printf("Enter your mail/s, use enter to enter a mail and '-1' to signal you finished\n");
fgets(tempMail, 50, stdin);
while (strcmp(tempMail, "-1\n") != 0) {
if ((strlen(tempMail) > 0) && (tempMail[strlen(tempMail) - 1] == '\n')) {
tempMail[strlen(tempMail) - 1] = '\0';
}
contacts[*nextAvailableP] = (char *)malloc((strlen(tempMail) + 1));
if (contacts[*nextAvailableP] == NULL) {
printf("Not enough memory");
return 0;
} else {
strcpy(contacts[*nextAvailableP], tempMail);
}
(*nextAvailableP)++;
numberOfMails++;
fgets(tempMail, 50, stdin);
}
strcpy(contacts[numberOfMailsIndex], intToString(numberOfMails - 1,10));
}
Your function add could be cut in a subfunction which gets a string from the user. This string will be stored in a allocated memory space which has the size of string.
Keep in mind : It's not a good practice to mix data of different nature in one array (names and email). It would be better to use structs (as #Barmar said).
I would do following steps:
Get name from user (char *)
Allocate memory and copy the name into it.
insert the pointer to this allocated memory into your array (contacts)
Get a email address put it in a dynamic allocated memory space
add its pointer to your array (Contacts
Increment emails counter
repeat
-1 detected
convert your email counter to string and the pointer into your array
Anyway here's a code that you can start play with:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_ENTRIES 50
#define BUFFERSIZE 50
int add(char *contacts[], int *nextAvailable);
char *getString(char *queryText);
char* intToString(int val, int base);
int main(void){
int i;
char *contacts[MAX_ENTRIES];
int nextAvailable = 0;
add(contacts, &nextAvailable);
add(contacts, &nextAvailable);
for(i=0; i < nextAvailable ; i++){
printf("%s", contacts[i]);
}
}
int add(char *contacts[], int *nextAvailable){
if(*nextAvailable > MAX_ENTRIES - 1){
printf("Not enough memory\n");
return 1;
}
contacts[*nextAvailable] = getString("Enter your name\n");
if(contacts[*nextAvailable] == NULL){
printf("Malloc Error\n");
return 1;
}
++(*nextAvailable);
int counterfield = *nextAvailable;
++(*nextAvailable);
int emailCounter = 0;
while(1){
if(*nextAvailable > MAX_ENTRIES - 1){
printf("Not enough memory\n");
return 1;
}
char *email = getString("Enter email\n");
if(strcmp(email, "-1\n") == 0){
contacts[counterfield] = malloc(5);
contacts[counterfield] = intToString(emailCounter, 10);
return 0;
}
emailCounter++;
contacts[*nextAvailable] = email;
++(*nextAvailable);
}
}
char *getString(char *queryText){
char buffer[BUFFERSIZE];
char *ret;
printf("%s", queryText);
fgets(buffer, BUFFERSIZE, stdin);
ret = malloc(strlen(buffer));
strcpy(ret, buffer);
return ret;
}
char* intToString(int val, int base){
//source: www.strudel.org.uk/itoa/
static char buf[32] = {0};
int i = 30;
for(; val && i ; --i, val /= base)
buf[i] = "0123456789abcdef"[val % base];
return &buf[i+1];
}
Related
I'm trying to count chars from input, and I noticed that while(getchar()!=EOF) produces an extra count, Is it because it counts the null-terminated from input?
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define LINE 5
#define MEM_SIZE 10
char *getInput(int *counter);
void printInput(char *input);
int main() {
char *mainInput;
int counter = 0;
printf("Please enter your input:\n");
mainInput = getInput(&counter);
if (mainInput == NULL) {
return 1;
}
printf("\n\n\nOutput:\n%s\n", mainInput);
printf("number of chars: %d\n", counter);
printInput(mainInput);
free(mainInput);
return 0;
}
char *getInput(int *counter) {
char *p = (char *)malloc(MEM_SIZE * sizeof(char));
char *q = p; /* backup pointer, if realloc fails to allocate, function will return last address values stored */
int c;
int temp_counter = 0;
long current = 0, last = MEM_SIZE - 1;
while ((c = getchar()) != EOF) {
if (current >= last) {
q = p;
p = (char *)realloc(q, last + (MEM_SIZE * sizeof(char)));
if (p == NULL) {
printf("Memory allocation failed, printing only stored values \n");
return q;
}
last += MEM_SIZE;
}
p[current] = c;
temp_counter++;
printf("number of chars: %d\n", temp_counter);
++current;
}
p[current] = '\0';
(*counter) = temp_counter - 1;
return p;
}
void printInput(char *input) {
int i, j = 0;
while (input[j] != '\0') {
for (i = 0; i < LINE; i++) {
if (input[j] == '\0')
break;
putchar(input[j]);
++j;
}
if (input[j] != '\0')
putchar('\n');
}
}
I'm stuck on an assignment I have to read from console really long number and then print it out using char* arr. Then I need to add and subtract number 1 array to number2 array. To be honest adding and subtracting I will probably deal on my own but I cannot figure out how to read those input characters, character by character and make while break after enter in console.
My code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int subtract(const char* number1, const char* number2, char** result){
if(number1 == NULL || number2 == NULL){
return 1;
}
return 0;
}
int add(const char* number1, const char* number2, char** result) {
if(number1 == NULL || number2 == NULL){
return 1;
}
return 0;
}
int input_check(int check, char* number) {
if (check != 1) {
return 1;
}
else {
return 0;
}
}
int main()
{
char* number1;
//char* number2;
//char** result;
int check = 0;
number1 = (char*)calloc(200,sizeof(char));
//number2 = (char*)calloc(200, sizeof(char));
//result = (char*)malloc(sizeof(char) * sizeof(char) * 400);
if (number1 == NULL) {
printf("Failed to allocate memory");
return 8;
}
printf("Input first num: ");
int i = 0;
while (1) {
char retVal;
scanf("%c", &retVal);
if (retVal >= 48 || retVal <= 57 || retVal != '\0') {
*(number1 + i) = retVal;
if ((number1 + i) == NULL) {
break;
}
printf("%d", atoi((number1 + i)));
i++;
}
else
{
break;
}
}
return 0;
}
Thanks for any help
As there is no limit on the numbers, you need to use dynamic memory allocation.
The straightforward (brute-force) way is to keep increasing the allocated size
char *input = calloc(1, 1); // space for '\0'
size_t len = 0;
for (;;) {
int ch = getchar();
if (ch != '\n') {
input[len] = ch; // replace '\0' with ch
len++;
char *tmp = realloc(input, len + 1);
if (tmp == NULL) exit(EXIT_FAILURE);
input = tmp;
input[len] = 0; // add '\0'
} else {
break;
}
}
// use input and len
free(input);
I am supposed to save every sequence of digits from a string in an array of chars , this is what i tried:
#include<stdio.h>
#include<ctype.h>
#include<string.h>
int check_number(char *s) {
for (; *s; ++s) {
if (!isdigit(*s))
return 0;
}
return 1;
}
void int_in_string(char *s, char **ar, int MaxCap) {
char temp[100];
int index = 0;
int i = 0;
for (; *s; s++) {
if (index == MaxCap) {
break;
}
if (isdigit(*s)) {
temp[i++] = *s;
}
if (*s == ' ' && check_number(temp)) {
ar[index++] = temp;
memset(temp, '\0', i);
i = 0;
}
}
if (index == 0) {
printf("no numbers in string");
}
for (int i = 0; i < index; i++)
printf(" %s \n", ar[i]);
}
but this code only prints several newlines , can someone explain me what i do wrong?
Some issues:
ar[index++]=temp;
This is just storing the same value (the address of temp) over and over. What you need to do is copy the string into the array.
Also, you need to terminate the string temp with '\0'. You handle this in all but the first string with memset(temp, '\0', i); However, since local variables are not initialized, you need to do it:
char temp[100] = {0}
Or, you can remove the initialization and the memset by just adding the EOS:
temp[i] = '\0';
Lastly, since you declare the original array as
char * ar[10];
You are not allocating any space for the strings. The simplest way to handle that is with strdup.
void int_in_string(char *s, char **ar, int MaxCap)
{
char temp[100];
int index = 0;
int i = 0;
for (; *s; s++) {
if (isdigit(*s)) {
temp[i++] = *s;
// Need to avoid buffer overflow
if (i == sizeof(temp)) {
i = 0;
}
}
if (isspace(*s)) {
temp[i] = '\0';
// strdup will allocate memory for the string, then copy it
ar[index++] = strdup(temp);
// if (NULL == ar[index-1]) TODO: Handle no memory error
i = 0;
if (index == MaxCap) {
break;
}
}
}
if (index == 0) {
printf("no numbers in string");
}
for (int i = 0; i < index; i++) {
printf(" %s \n", ar[i]);
// free the mem from strdup
free(ar[i]);
}
}
I believe some systems may not have strdup(). If not, it can be easily replicated:
char * my_strdup(const char *src)
{
if (src == NULL) return NULL;
char *dest = malloc(strlen(src) + 1);
if (dest == NULL) return NULL;
strcpy(dest, src);
return dest;
}
I am writing a tool to scan all the nodes on a network but I have ran in to a problem. I'm writing the tool in C but I'm new to the language so I'm not sure how the iterate through the address range.
The user will give the argument 192.168.*.* and it will create every IP address in that range, e.g. 192.168.1.1, 192.168.1.2, 192.168.1.3 and then eventually 192.168.2.1, 192.168.2.2, 192.168.2.3 etc.
My previous code was:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void scanner(int s)
{
char addr[20];
for (int i = 0; i < 255; ++i)
{
sprintf(addr, "192.168.%d.%d", s, i);
printf("%s\n", addr);
}
}
int main()
{
for (int i = 0; i < 255; ++i)
{
scanner(i);
}
return 0;
}
But I don't know how to run this from the user input.
You can take the inputs from the user using the scanf function. I have updated your code to use the same -
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int addr_byte_0;
int addr_byte_1;
void scanner(int s)
{
char addr[200];
int i;
for (i = 0; i < 255; ++i)
{
sprintf(addr, "%d.%d.%d.%d", addr_byte_0, addr_byte_1, s, i);
printf("%s\n", addr);
}
}
int main()
{
int i;
//printf("Enter the first byte of the address: ");
scanf ("%d", &addr_byte_0);
//printf("Enter the second byte of the address: ");
scanf ("%d", &addr_byte_1);
for (i = 0; i < 255; ++i)
{
scanner(i);
}
return 0;
}
Also, as per C standards you cannot declare a variable inside the for loop. Hence I have moved the declaration out of the for loop. Hope this helps!
Inspired by (e.g. python-) generators, my solution doesn't perform dynamic memory allocation and and has constant memory consumption. I don't like that I currently rely on a do while loop. Also the explicit check for ig->num_wildcards == 0 is ugly. Anyways:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define IP_OCTETS 4
#define MAX_UCHAR 255
typedef struct {
int wildcard_pos[IP_OCTETS];
int num_wildcards;
int counter[IP_OCTETS];
int octet[IP_OCTETS];
} ip_generator;
char* mystrsep(char** stringp, const char* delim)
{
char* start = *stringp;
char* p;
p = (start != NULL) ? strpbrk(start, delim) : NULL;
if (p == NULL)
{
*stringp = NULL;
}
else
{
*p = '\0';
*stringp = p + 1;
}
return start;
}
void init_ip_gen(ip_generator *ig, char* ip_mask)
{
char *token, *string;
char* ip_mask_ptr = ip_mask;
const char delimiters[] = ".";
int i = 0;
while ((token = mystrsep(&ip_mask_ptr, delimiters)) != NULL)
{
ig->wildcard_pos[i] = -1;
if (strcmp(token, "*") == 0)
{
ig->wildcard_pos[ig->num_wildcards] = i;
ig->counter[ig->num_wildcards] = 1;
ig->num_wildcards++;
}
else
{
ig->octet[i] = atoi(token);
}
i++;
}
}
int ig_next(ip_generator *ig)
{
int i;
int carry = 1;
if (ig->num_wildcards == 0)
{
return 0;
}
for (i = ig->num_wildcards - 1; i >= 0; i--)
{
if (carry == 1)
{
if (ig->counter[i] == MAX_UCHAR)
{
ig->counter[i] = 1;
}
else
{
ig->counter[i]++;
carry = 0;
}
}
if (carry == 0)
{
break;
}
if (i == 0 && carry == 1)
{
return 0;
}
}
return 1;
}
void generate_ip(ip_generator *ig, char *ip)
{
int i;
int j = 0;
int oct[IP_OCTETS];
for (i = 0; i < IP_OCTETS; i++)
{
if (i == ig->wildcard_pos[j])
{
oct[i] = ig->counter[j];
j++;
}
else
{
oct[i] = ig->octet[i];
}
}
sprintf(ip, "%d.%d.%d.%d", oct[0], oct[1], oct[2], oct[3]);
}
int main()
{
char ip_mask[] = "192.*.10.*";
//char ip_mask[] = "192.1.10.123";
ip_generator ig;
memset(&ig, 0, sizeof(ig));
init_ip_gen(&ig, ip_mask);
char ip[32];
memset(ip, 0, sizeof(ip));
do
{
generate_ip(&ig, ip);
printf("%s\n", ip);
} while (ig_next(&ig));
return 0;
}
I have the following code to accept any number of lines from the user and print out the ones whose length is > 80 characters :-
#include <stdio.h>
#include <stdlib.h>
#include "shared.h"
#include <string.h>
int MAXLINE = 10;
int INCREMENT = 10;
int NUM = 1;
char* longest = NULL;
char* line = NULL;
char** row = NULL;
void _memcleanup(){
int i =0;
free(line);
free(longest);
for(i=0;i<NUM;i++){
free(row[i]);
}
free(row);
}
void print_lines(int len){
int i;
for(i=0;i<len;i++){
if(strlen(row[i])>80){
printf("%s\n",row[i]);
}
}
}
void copy(char** longest, char** line){
int i=0;
char* temp = realloc(*longest,(MAXLINE)*sizeof(char));
if(temp == NULL){
printf("%s","Unable to allocate memory");
_memcleanup();
exit(1);
}
*longest = temp;
while(((*longest)[i] = (*line)[i]) != '\0'){
++i;
}
longest[i] = '\0';
}
void store(char** s, int pos){
int i=0;
char* temp = realloc(row[pos],(MAXLINE)*sizeof(char));
if(temp == NULL){
printf("%s","Unable to allocate memory");
_memcleanup();
exit(1);
}
row[pos] = temp;
while((row[pos][i] = (*s)[i]) != '\0'){
++i;
}
row[pos][i] = '\0';
}
int _getline(char** s, int pos){
int i,c;
for(i=0; ((c=getchar())!=EOF && c!='\n'); i++){
if(i == MAXLINE - 2){
char* temp = realloc(*s,(MAXLINE + INCREMENT)*sizeof(char));
if(temp == NULL){
printf("%s","Unable to allocate memory");
_memcleanup();
exit(1);
}
*s= temp;
MAXLINE += INCREMENT;
}
(*s)[i] = c;
}
if(c == '\n'){
(*s)[i++] = c;
}
(*s)[i]= '\0';
store(s, pos);
return i;
}
int main(){
int max=0, len, i=0;
line = malloc(MAXLINE*sizeof(char));
longest = malloc(MAXLINE*sizeof(char));
//array of character pointers
row = malloc(NUM*sizeof(char*));
//allocate memory for each row in the array
for(i = 0; i < NUM; i++){
row[i]= malloc(MAXLINE*(sizeof(char)));
}
i=0;
//for(i=0; len = _getline(&line)) > 0; i++){
while((len = _getline(&line, i)) > 0){
printf("%d %d", len, MAXLINE);
/* if(len > max){ */
/* max = len; */
/* copy(&longest, &line); */
/* } */
i++;
}
/* if(max>0){ */
/* printf("%s",longest); */
/* } */
print_lines(i);
_memcleanup();
return 0;
}
The idea that i am following is to reallocate the 2D array when the number of lines exceed NUM. Now to test it out, i set NUM as 1. However, even after doing so, the program gladly accepts upto 3 inputs and segfaults on the 4th input i.e. pos=3 in the program's context.
Why does it accept 3 inputs (ideally it should give a segfault pos=1 itself since i have given size as only 1 and i am not allocating more space for the 2D array)
Working code is as follows:
#include <stdio.h>
#include <stdlib.h>
#include "shared.h"
#include <string.h>
int MAXLINE = 10;
int INCREMENT = 10;
int NUM = 1;
char* longest = NULL;
char* line = NULL;
char** row = NULL;
void _memcleanup(){
int i =0;
free(line);
free(longest);
for(i=0;i<NUM;i++){
free(row[i]);
}
free(row);
}
void print_lines(int len){
int i;
for(i=0;i<len;i++){
if(strlen(row[i])>80){
printf("%s\n",row[i]);
}
}
}
void copy(char** longest, char** line){
int i=0;
char* temp = realloc(*longest,(MAXLINE)*sizeof(char));
if(temp == NULL){
printf("%s","Unable to allocate memory");
_memcleanup();
exit(1);
}
*longest = temp;
while(((*longest)[i] = (*line)[i]) != '\0'){
++i;
}
longest[i] = '\0';
}
void store(char** s, int pos){
int i=0;
if(pos == NUM){
char** temprow = realloc(row, (NUM + INCREMENT)*sizeof(char*));
if(temprow == NULL){
printf("%s","Unable to allocate memory");
_memcleanup();
exit(1);
}
row = temprow;
//allocate space for extra elements
for(i=NUM;i<NUM+INCREMENT;i++){
row[i] = malloc(MAXLINE*sizeof(char));
}
NUM = NUM + INCREMENT;
}
char* temp = realloc(row[pos],(MAXLINE)*sizeof(char));
if(temp == NULL){
printf("%s","Unable to allocate memory");
_memcleanup();
exit(1);
}
row[pos] = temp;
while((row[pos][i] = (*s)[i]) != '\0'){
++i;
}
row[pos][i] = '\0';
}
int _getline(char** s, int pos){
int i,c;
for(i=0; ((c=getchar())!=EOF && c!='\n'); i++){
if(i == MAXLINE - 2){
char* temp = realloc(*s,(MAXLINE + INCREMENT)*sizeof(char));
if(temp == NULL){
printf("%s","Unable to allocate memory");
_memcleanup();
exit(1);
}
*s= temp;
MAXLINE += INCREMENT;
}
(*s)[i] = c;
}
if(c == '\n'){
(*s)[i++] = c;
}
(*s)[i]= '\0';
store(s, pos);
return i;
}
int main(){
int max=0, len, i=0;
line = malloc(MAXLINE*sizeof(char));
longest = malloc(MAXLINE*sizeof(char));
//array of character pointers
row = malloc(NUM*sizeof(char*));
//allocate memory for each row in the array
for(i = 0; i < NUM; i++){
row[i]= malloc(MAXLINE*(sizeof(char)));
}
i=0;
//for(i=0; len = _getline(&line)) > 0; i++){
while((len = _getline(&line, i)) > 0){
printf("%d %d", len, MAXLINE);
/* if(len > max){ */
/* max = len; */
/* copy(&longest, &line); */
/* } */
i++;
}
/* if(max>0){ */
/* printf("%s",longest); */
/* } */
print_lines(i);
_memcleanup();
return 0;
}
You are asking:
Why does it accept 3 inputs (ideally it should give a segfault pos=1 itself since i have given size as only 1 and i am not allocating more space for the 2D array)
and you are right, that if you allocate memory for one row only, it invokes Undefined Behaviour if you attempt to access rows[1]. But that behaviour is just -- undefined -- what means that you can't rely on the program crashing. Anything might happen, including that the program seems to work flawlessly
In the main(), instead of using
while((len = _getline(&line, i)) > 0){
use
while(i< NUM)
{
len = _getline(&line, i);
For me with this code change, it worked correctly.